import { resolve } from 'node:path';

import { skipOnboarding, test } from '@affine-test/kit/playwright';
import {
  addUserToWorkspace,
  createRandomUser,
  enableCloudWorkspace,
  enableCloudWorkspaceFromShareButton,
  loginUser,
} from '@affine-test/kit/utils/cloud';
import { clickEdgelessModeButton } from '@affine-test/kit/utils/editor';
import {
  clickNewPageButton,
  getBlockSuiteEditorTitle,
  waitForEditorLoad,
} from '@affine-test/kit/utils/page-logic';
import { clickUserInfoCard } from '@affine-test/kit/utils/setting';
import {
  clickSideBarCurrentWorkspaceBanner,
  clickSideBarSettingButton,
} from '@affine-test/kit/utils/sidebar';
import { createLocalWorkspace } from '@affine-test/kit/utils/workspace';
import { expect } from '@playwright/test';

let user: {
  id: string;
  name: string;
  email: string;
  password: string;
};

test.beforeEach(async () => {
  user = await createRandomUser();
});

test.beforeEach(async ({ page }) => {
  await loginUser(page, user.email);
});

test('can enable share page', async ({ page, browser }) => {
  await page.reload();
  await waitForEditorLoad(page);
  await createLocalWorkspace(
    {
      name: 'test',
    },
    page
  );
  await enableCloudWorkspaceFromShareButton(page);
  const title = getBlockSuiteEditorTitle(page);
  await title.pressSequentially('TEST TITLE', {
    delay: 50,
  });
  await page.keyboard.press('Enter', { delay: 50 });
  await page.keyboard.type('TEST CONTENT', { delay: 50 });
  await page.getByTestId('cloud-share-menu-button').click();
  await page.getByTestId('share-menu-create-link-button').click();
  await page.getByTestId('share-menu-copy-link-button').click();

  // check share page is accessible
  {
    const context = await browser.newContext();
    await skipOnboarding(context);
    const url: string = await page.evaluate(() =>
      navigator.clipboard.readText()
    );
    const page2 = await context.newPage();
    await page2.goto(url);
    await waitForEditorLoad(page2);
    const title = getBlockSuiteEditorTitle(page2);
    await expect(title).toContainText('TEST TITLE');
    expect(page2.locator('affine-paragraph').first()).toContainText(
      'TEST CONTENT'
    );
  }
});

test('share page with default edgeless', async ({ page, browser }) => {
  await page.reload();
  await waitForEditorLoad(page);
  await createLocalWorkspace(
    {
      name: 'test',
    },
    page
  );
  await enableCloudWorkspaceFromShareButton(page);
  const title = getBlockSuiteEditorTitle(page);
  await title.pressSequentially('TEST TITLE', {
    delay: 50,
  });
  await page.keyboard.press('Enter', { delay: 50 });
  await page.keyboard.type('TEST CONTENT', { delay: 50 });
  await clickEdgelessModeButton(page);
  await expect(page.locator('affine-edgeless-root')).toBeVisible({
    timeout: 1000,
  });
  await page.getByTestId('cloud-share-menu-button').click();
  await page.getByTestId('share-menu-create-link-button').click();
  await page.getByTestId('share-menu-copy-link-button').click();

  // check share page is accessible
  {
    const context = await browser.newContext();
    await skipOnboarding(context);
    const url: string = await page.evaluate(() =>
      navigator.clipboard.readText()
    );
    const page2 = await context.newPage();
    await page2.goto(url);
    await waitForEditorLoad(page2);
    await expect(page.locator('affine-edgeless-root')).toBeVisible({
      timeout: 1000,
    });
    expect(page2.locator('affine-paragraph').first()).toContainText(
      'TEST CONTENT'
    );
    const editButton = page2.getByTestId('share-page-edit-button');
    await expect(editButton).not.toBeVisible();
  }
});

test('can collaborate with other user and name should display when editing', async ({
  page,
  browser,
}) => {
  await page.reload();
  await waitForEditorLoad(page);
  await createLocalWorkspace(
    {
      name: 'test',
    },
    page
  );
  await enableCloudWorkspace(page);
  await clickNewPageButton(page);
  const currentUrl = page.url();
  // format: http://localhost:8080/workspace/${workspaceId}/xxx
  const workspaceId = currentUrl.split('/')[4];
  const userB = await createRandomUser();
  const context = await browser.newContext();
  await skipOnboarding(context);
  const page2 = await context.newPage();
  await loginUser(page2, userB.email);
  await addUserToWorkspace(workspaceId, userB.id, 1 /* READ */);
  await page2.reload();
  await waitForEditorLoad(page2);
  await page2.goto(currentUrl);
  {
    const title = getBlockSuiteEditorTitle(page);
    await title.pressSequentially('TEST TITLE', {
      delay: 50,
    });
  }
  await page2.waitForTimeout(200);
  {
    const title = getBlockSuiteEditorTitle(page2);
    await expect(title).toHaveText('TEST TITLE');
    const typingPromise = (async () => {
      await page.keyboard.press('Enter', { delay: 50 });
      await page.keyboard.type('TEST CONTENT', { delay: 50 });
    })();
    // username should be visible when editing
    await expect(page2.getByText(user.name)).toBeVisible();
    await typingPromise;
  }

  // change username
  await clickSideBarSettingButton(page);
  await clickUserInfoCard(page);
  const input = page.getByTestId('user-name-input');
  await input.clear();
  await input.pressSequentially('TEST USER', {
    delay: 50,
  });
  await page.getByTestId('save-user-name').click({
    delay: 50,
  });
  await page.keyboard.press('Escape', {
    delay: 50,
  });
  const title = getBlockSuiteEditorTitle(page);
  await title.focus();
  await page.keyboard.press('ArrowDown', { delay: 50 });
  {
    await expect(page2.getByText('TEST USER')).toBeVisible({
      timeout: 2000,
    });
  }
});

test('can sync collections between different browser', async ({
  page,
  browser,
}) => {
  await page.reload();
  await waitForEditorLoad(page);
  await createLocalWorkspace(
    {
      name: 'test',
    },
    page
  );
  await enableCloudWorkspace(page);
  await page.getByTestId('slider-bar-add-collection-button').click();
  const title = page.getByTestId('input-collection-title');
  await title.isVisible();
  await title.fill('test collection');
  await page.getByTestId('save-collection').click();

  {
    const context = await browser.newContext();
    await skipOnboarding(context);
    const page2 = await context.newPage();
    await loginUser(page2, user.email);
    await page2.goto(page.url());
    const collections = page2.getByTestId('collections');
    await expect(collections.getByText('test collection')).toBeVisible();
  }
});

test('can sync svg between different browsers', async ({ page, browser }) => {
  await page.reload();
  await waitForEditorLoad(page);
  await createLocalWorkspace(
    {
      name: 'test',
    },
    page
  );
  await enableCloudWorkspace(page);
  await clickNewPageButton(page);
  await waitForEditorLoad(page);

  // upload local svg

  const slashMenu = page.locator(`.slash-menu`);
  const image = page.locator('affine-image');

  await page.evaluate(async () => {
    // https://github.com/toeverything/blocksuite/blob/master/packages/blocks/src/_common/utils/filesys.ts#L20
    (window as any).showOpenFilePicker = undefined;
  });

  const title = getBlockSuiteEditorTitle(page);
  await title.pressSequentially('TEST TITLE', {
    delay: 50,
  });
  await page.keyboard.press('Enter', { delay: 50 });
  await page.waitForTimeout(100);
  await page.keyboard.type('/', { delay: 50 });
  await expect(slashMenu).toBeVisible();
  await page.keyboard.type('image', { delay: 100 });
  await expect(slashMenu).toBeVisible();
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.keyboard.press('Enter', { delay: 50 });
  const fileChooser = await fileChooserPromise;
  fileChooser.setFiles(resolve(__dirname, 'logo.svg'));
  await expect(image).toBeVisible();

  // the user should see the svg
  // get the image src under "affine-image img"
  const src1 = await page.locator('affine-image img').getAttribute('src');
  expect(src1).not.toBeNull();

  // fetch the actual src1 resource in the browser
  const svg1 = await page.evaluate(
    src =>
      fetch(src!)
        .then(res => res.blob())
        .then(blob => blob.text()),
    src1
  );

  {
    const context = await browser.newContext();
    await skipOnboarding(context);
    const page2 = await context.newPage();
    await loginUser(page2, user.email);
    await page2.goto(page.url());

    // second user should see the svg
    // get the image src under "affine-image img"
    const src2 = await page2.locator('affine-image img').getAttribute('src');
    expect(src2).not.toBeNull();

    // fetch the actual src2 resource in the browser
    const svg2 = await page2.evaluate(
      src =>
        fetch(src!)
          .then(res => res.blob())
          .then(blob => blob.text()),
      src2
    );

    expect(svg2).toEqual(svg1);
  }
});

test('When the first sync is not completed, should always show loading', async ({
  page,
  browser,
}) => {
  await page.reload();
  await waitForEditorLoad(page);
  await createLocalWorkspace(
    {
      name: 'test',
    },
    page
  );
  await enableCloudWorkspace(page);
  await clickNewPageButton(page);
  await waitForEditorLoad(page);
  const title = getBlockSuiteEditorTitle(page);
  await title.pressSequentially('TEST TITLE', {
    delay: 50,
  });

  const context = await browser.newContext();
  await skipOnboarding(context);
  const page2 = await context.newPage();
  await loginUser(page2, user.email);

  // simulate sync stuck
  await page2.evaluate(() => {
    (window as any)._TEST_SIMULATE_SYNC_LAG = new Promise(() => {});
  });
  const localWorkspaceUrl = page2.url();
  await clickSideBarCurrentWorkspaceBanner(page2);
  await page2.getByTestId('workspace-card').getByText('test').click(); // enter "test" workspace

  await page2.waitForTimeout(1000);

  await expect(
    page2.getByTestId('page-list-item').getByText('TEST TITLE')
  ).not.toBeVisible(); // should be loading

  // Simulate user refresh and re-enter workspace, should still be loading
  await page2.goto(localWorkspaceUrl);

  // setup sync lag
  await page2.evaluate(() => {
    (window as any).resolveSyncLag = null;
    (window as any)._TEST_SIMULATE_SYNC_LAG = new Promise(resolve => {
      (window as any).resolveSyncLag = resolve;
    });
  });
  await clickSideBarCurrentWorkspaceBanner(page2);
  await page2.getByTestId('workspace-card').getByText('test').click(); // enter "test" workspace

  await page2.waitForTimeout(1000);

  await expect(
    page2.getByTestId('page-list-item').getByText('TEST TITLE')
  ).not.toBeVisible(); // should be loading

  await page2.evaluate(() => {
    (window as any).resolveSyncLag();
  }); // start syncing
  await page2.getByTestId('page-list-item').getByText('TEST TITLE').click(); // should be able to click page
  await waitForEditorLoad(page2);

  expect(await getBlockSuiteEditorTitle(page2).innerText()).toContain(
    'TEST TITLE'
  );
});
