import { test, expect } from '@playwright/test';

test.describe('events', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/e2e/events');
    page.on('pageerror', (err) => expect(err).toEqual(undefined));
    page.on('console', (msg) => {
      // console.log(msg.type(), msg.text());
      if (msg.type() === 'error') {
        expect(msg.text()).toEqual(undefined);
      }
    });
  });

  test('should rerender correctly', async ({ page }) => {
    const btnWrapped = page.locator('#btn-wrapped');
    const btnTransparent = page.locator('#btn-transparent');
    const contentTransparent = page.locator('#count-transparent');
    const countWrapped = page.locator('#count-wrapped');

    await expect(contentTransparent).toHaveText('countTransparent: 0');
    await expect(countWrapped).toHaveText('countWrapped: 0');
    await expect(btnWrapped).toHaveText('Wrapped 0');

    // Click wrapped
    await btnWrapped.click();
    await expect(countWrapped).toHaveText('countWrapped: 1');
    await expect(btnWrapped).toHaveText('Wrapped 1');
    await expect(contentTransparent).toHaveText('countTransparent: 0');

    // Click wrapped
    await btnWrapped.click();
    await expect(countWrapped).toHaveText('countWrapped: 2');
    await expect(btnWrapped).toHaveText('Wrapped 2');
    await expect(contentTransparent).toHaveText('countTransparent: 0');

    // Click transparent
    await btnTransparent.click();
    await expect(contentTransparent).toHaveText('countTransparent: 1');
    await expect(countWrapped).toHaveText('countWrapped: 2');
    await expect(btnWrapped).toHaveText('Wrapped 2');

    // Click transparent
    await btnTransparent.click();
    await expect(contentTransparent).toHaveText('countTransparent: 2');
    await expect(countWrapped).toHaveText('countWrapped: 2');
    await expect(btnWrapped).toHaveText('Wrapped 2');
  });

  test('should prevent defaults and bubbling', async ({ page }) => {
    const prevented1 = page.locator('#prevent-default-1');
    const prevented2 = page.locator('#prevent-default-2');
    const countWrapped = page.locator('#count-anchor');

    await prevented1.click();
    await expect(countWrapped).toHaveText('countAnchor: 0');

    await prevented2.click();
    await expect(countWrapped).toHaveText('countAnchor: 1');
  });

  test('should prevent redirect when clicking a child button inside a prevented anchor', async ({
    page,
  }) => {
    const childButton = page.locator('#prevent-default-child-button');

    await childButton.click();

    await expect(page).toHaveURL(/\/e2e\/events$/);
    await expect(page.locator('#count-nested-anchor')).toHaveText('countNestedAnchor: 1');
    await expect(page.locator('#count-nested-button')).toHaveText('countNestedButton: 1');
  });

  test('should preserve mouseleave and mouseover execution order', async ({ page }) => {
    const red = page.locator('#hover-order-red');
    const blue = page.locator('#hover-order-blue');

    await red.hover();
    await blue.hover();

    await expect(page.locator('#hover-order-log')).toHaveText('red mouse out|blue mouse in');
  });

  test(`GIVEN "stoppropagation" is set as a attribute 
        THEN it should stop propagation`, async ({ page }) => {
    const stoppedPropagationButton = page.locator('#stop-propagation');

    const countPropagation = page.locator('#count-propagation');
    await expect(countPropagation).toHaveText('countPropagationStopped: 0');

    await stoppedPropagationButton.click();

    await expect(countPropagation).toHaveText('countPropagationStopped: 1');
  });

  test('issue 3948 - useOn window conditional render', async ({ page }) => {
    const always = page.locator('#issue-3948-always');
    const toggle = page.locator('#issue-3948-toggle');
    const html = page.locator('html');
    await expect(always).toHaveText('always count: 0');

    await html.click();
    await expect(always).toHaveText('always count: 1');
    await toggle.click();
    const conditional = page.locator('#issue-3948-conditional');
    await expect(conditional).toHaveText('conditional count: 0');

    await html.click();
    await expect(always).toHaveText('always count: 3');
    await expect(conditional).toHaveText('conditional count: 1');

    await html.click();
    await expect(always).toHaveText('always count: 4');
    await expect(conditional).toHaveText('conditional count: 2');
  });
});

test.describe('events with client rerender', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/e2e/events');
    page.on('pageerror', (err) => expect(err).toEqual(undefined));
    page.on('console', (msg) => {
      if (msg.type() === 'error') {
        expect(msg.text()).toEqual(undefined);
      }
    });
  });

  function eventsTest(isClient: boolean) {
    test('should not throw if event handler is array with undefined value', async ({ page }) => {
      const button = page.locator('#undefined-event-handler');
      await button.click();
      await expect(button).toHaveText('Should not throw');
    });

    test('should execute all event handlers', async ({ page }) => {
      const button = page.locator('#execute-all-event-handlers');
      await expect(button).toHaveText('1 / 1');
      await button.click();
      await expect(button).toHaveText('2 / 3');
    });

    test('should handle passive event scopes', async ({ page }) => {
      const regularClick = page.locator('#passive-regular-click');
      const passiveClick = page.locator('#passive-click');
      const passivePreventDefault = page.locator('#passive-preventdefault');
      const passiveDocument = page.locator('#passive-document');
      const passiveWindow = page.locator('#passive-window');

      if (!isClient) {
        await expect(regularClick).toHaveAttribute('q-e:click');
        await expect(regularClick).not.toHaveAttribute('q-ep:click');

        await expect(passiveClick).toHaveAttribute('q-ep:click');
        await expect(passiveClick).not.toHaveAttribute('q-e:click');
        await expect(passiveClick).not.toHaveAttribute('passive:click');

        await expect(passiveDocument).toHaveAttribute('q-dp:touchstart');
        await expect(passiveDocument).not.toHaveAttribute('q-d:touchstart');
        await expect(passiveDocument).not.toHaveAttribute('passive:touchstart');

        await expect(passiveWindow).toHaveAttribute('q-wp:scroll');
        await expect(passiveWindow).not.toHaveAttribute('q-w:scroll');
        await expect(passiveWindow).not.toHaveAttribute('passive:scroll');
      }

      await regularClick.click();
      await passiveClick.click();

      await expect(page.locator('#count-passive-regular-click')).toHaveText(
        'countPassiveRegularClick: 1'
      );
      await expect(page.locator('#count-passive-click')).toHaveText('countPassiveClick: 1');

      await passivePreventDefault.click();
      await expect(page.locator('#count-passive-preventdefault')).toHaveText(
        'countPassivePreventDefault: 1'
      );
      await expect(page.locator('#state-passive-preventdefault')).toHaveText(
        'passivePreventDefaultState: false'
      );

      await page.evaluate(() => {
        document.dispatchEvent(new Event('touchstart', { bubbles: true, cancelable: true }));
        window.dispatchEvent(new Event('scroll'));
      });

      await expect(page.locator('#count-passive-document')).toHaveText('countPassiveDocument: 1');
      await expect(page.locator('#count-passive-window')).toHaveText('countPassiveWindow: 1');
    });
  }

  eventsTest(false);

  test.describe('client rerender', () => {
    test.beforeEach(async ({ page }) => {
      const toggleRender = page.locator('#rerender');
      await toggleRender.click();
      await expect(page.locator('#render-count')).toHaveText('1');
    });
    eventsTest(true);
  });
});

test.describe('broadcast-events', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/e2e/broadcast-events');
    page.on('pageerror', (err) => expect(err).toEqual(undefined));
    page.on('console', (msg) => {
      if (msg.type() === 'error') {
        expect(msg.text()).toEqual(undefined);
      }
    });
  });

  function tests() {
    test('should render correctly', async ({ page }) => {
      const document = page.locator('p.document');
      const document2 = page.locator('p.document2');

      const window = page.locator('p.window');
      const window2 = page.locator('p.window2');

      const self = page.locator('p.self');
      const self2 = page.locator('p.self2');

      await expect(document).toHaveText('(Document: x: 0, y: 0)');
      await expect(document2).toHaveText('(Document2: x: 0, y: 0)');
      await expect(window).toHaveText('(Window: x: 0, y: 0)');
      await expect(window2).toHaveText('(Window2: x: 0, y: 0)');
      await expect(self).toHaveText('(Host: x: 0, y: 0, inside: false)');
      await expect(self2).toHaveText('(Host2: x: 0, y: 0)');

      await page.mouse.move(100, 50);

      await expect(document).toHaveText('(Document: x: 100, y: 50)');
      await expect(document2).toHaveText('(Document2: x: 100, y: 50)');
      await expect(window).toHaveText('(Window: x: 100, y: 50)');
      await expect(window2).toHaveText('(Window2: x: 100, y: 50)');
      await expect(self).toHaveText('(Host: x: 0, y: 0, inside: false)');
      await expect(self2).toHaveText('(Host2: x: 0, y: 0)');

      await page.mouse.move(100, 300);

      await expect(document).toHaveText('(Document: x: 100, y: 300)');
      await expect(document2).toHaveText('(Document2: x: 100, y: 300)');
      await expect(window).toHaveText('(Window: x: 100, y: 300)');
      await expect(window2).toHaveText('(Window2: x: 100, y: 300)');
      await expect(self).toHaveText('(Host: x: 100, y: 300, inside: true)');
      await expect(self2).toHaveText('(Host2: x: 100, y: 300)');
    });
  }

  tests();

  test.describe('client rerender', () => {
    test.beforeEach(async ({ page }) => {
      const toggleRender = page.locator('#btn-toggle-render');
      await toggleRender.click();
      await page.waitForTimeout(100);
    });
    tests();
  });
});

test.describe('events client side', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/e2e/events-client');
    page.on('pageerror', (err) => expect(err).toEqual(undefined));
    page.on('console', (msg) => {
      if (msg.type() === 'error') {
        expect(msg.text()).toEqual(undefined);
      }
    });
  });

  test('should progressively listen to new events', async ({ page }) => {
    const link = page.locator('#link');
    const input = page.locator('#input');

    // it should do nothing, no navigate
    await link.click();

    await input.focus();

    const div = page.locator('#div');
    await expect(div).toHaveText('Text: ');
    await expect(div).toHaveClass('');

    await input.fill('Some text');
    await expect(div).toHaveText('Text: Some text');
    await expect(div).toHaveClass('');

    await div.hover();
    await expect(div).toHaveClass('isOver');
  });
});
