import { expect, test } from '../../fixtures/webdav.fixture';
import { SyncPage } from '../../pages/sync.page';
import { WorkViewPage } from '../../pages/work-view.page';
import { ProjectPage } from '../../pages/project.page';
import { waitForStatePersistence } from '../../utils/waits';
import {
  createSyncFolder,
  generateSyncFolderName,
  setupSyncClient,
  waitForSyncComplete,
  WEBDAV_CONFIG_TEMPLATE,
} from '../../utils/sync-helpers';

// Timing constants for sync detection

const WEBDAV_TIMESTAMP_DELAY_MS = 2000;

test.describe('@webdav WebDAV Sync Expansion', () => {
  // Run sync tests serially to avoid WebDAV server contention
  test.describe.configure({ mode: 'serial' });

  test('should sync projects', async ({ browser, baseURL, request }) => {
    test.slow();
    const SYNC_FOLDER_NAME = generateSyncFolderName('e2e-expansion-proj');
    await createSyncFolder(request, SYNC_FOLDER_NAME);
    const WEBDAV_CONFIG = {
      ...WEBDAV_CONFIG_TEMPLATE,
      syncFolderPath: `/${SYNC_FOLDER_NAME}`,
    };

    const url = baseURL || 'http://localhost:4242';

    // --- Client A ---
    const { context: contextA, page: pageA } = await setupSyncClient(browser, url);
    const syncPageA = new SyncPage(pageA);
    const workViewPageA = new WorkViewPage(pageA);
    const projectPageA = new ProjectPage(pageA);
    await workViewPageA.waitForTaskList();

    // Configure Sync A
    await syncPageA.setupWebdavSync(WEBDAV_CONFIG);

    // Create Project on A
    const projectName = 'Synced Project';
    await projectPageA.createProject(projectName);

    // Navigate to the newly created project (createProject doesn't auto-navigate)
    await projectPageA.navigateToProjectByName(projectName);

    // Add task to new project on A
    await workViewPageA.addTask('Task in Project A');

    // Sync A
    await syncPageA.triggerSync();
    await waitForSyncComplete(pageA, syncPageA);

    // --- Client B ---
    const { context: contextB, page: pageB } = await setupSyncClient(browser, url);
    const syncPageB = new SyncPage(pageB);
    const workViewPageB = new WorkViewPage(pageB);
    const projectPageB = new ProjectPage(pageB);
    await workViewPageB.waitForTaskList();

    // Configure Sync B
    await syncPageB.setupWebdavSync(WEBDAV_CONFIG);
    await syncPageB.triggerSync();
    await waitForSyncComplete(pageB, syncPageB);

    // Wait for state persistence to complete after sync
    await waitForStatePersistence(pageB);

    // Navigate to the synced project — navigateToProjectByName handles expanding
    // the Projects group, waiting for the tree item to appear, and clicking it.
    await projectPageB.navigateToProjectByName(projectName);

    // Verify task
    await expect(pageB.locator('task')).toHaveCount(1);
    await expect(pageB.locator('task').first()).toContainText('Task in Project A');

    // Add task on B in project
    await workViewPageB.addTask('Task in Project B');

    // Wait for state persistence before syncing
    await waitForStatePersistence(pageB);

    await syncPageB.triggerSync();
    await waitForSyncComplete(pageB, syncPageB);

    // Wait for server to process and ensure Last-Modified timestamp differs
    // WebDAV servers often have second-level timestamp precision
    await pageB.waitForTimeout(WEBDAV_TIMESTAMP_DELAY_MS);

    // Sync A - trigger sync to download changes from B
    await syncPageA.triggerSync();
    await waitForSyncComplete(pageA, syncPageA);

    // Wait for state persistence to complete after sync
    await waitForStatePersistence(pageA);

    // Navigate to project page to verify task synced
    await projectPageA.navigateToProjectByName(projectName);

    // Check if task B is visible immediately after sync (no reload)
    await expect(pageA.locator('task', { hasText: 'Task in Project B' })).toBeVisible({
      timeout: 20000,
    });

    await contextA.close();
    await contextB.close();
  });

  test('should sync task done state', async ({ browser, baseURL, request }) => {
    test.slow();
    const SYNC_FOLDER_NAME = generateSyncFolderName('e2e-expansion-done');
    await createSyncFolder(request, SYNC_FOLDER_NAME);
    const WEBDAV_CONFIG = {
      ...WEBDAV_CONFIG_TEMPLATE,
      syncFolderPath: `/${SYNC_FOLDER_NAME}`,
    };

    const url = baseURL || 'http://localhost:4242';

    // --- Client A ---
    const { context: contextA, page: pageA } = await setupSyncClient(browser, url);
    const syncPageA = new SyncPage(pageA);
    const workViewPageA = new WorkViewPage(pageA);
    await workViewPageA.waitForTaskList();

    await syncPageA.setupWebdavSync(WEBDAV_CONFIG);

    const taskName = 'Task to be done';
    await workViewPageA.addTask(taskName);

    await syncPageA.triggerSync();
    await waitForSyncComplete(pageA, syncPageA);

    // --- Client B ---
    const { context: contextB, page: pageB } = await setupSyncClient(browser, url);
    const syncPageB = new SyncPage(pageB);
    const workViewPageB = new WorkViewPage(pageB);
    await workViewPageB.waitForTaskList();

    // Configure Sync B
    await syncPageB.setupWebdavSync(WEBDAV_CONFIG);
    await syncPageB.triggerSync();
    await waitForSyncComplete(pageB, syncPageB);

    // Wait for state persistence to complete after sync
    await waitForStatePersistence(pageB);

    // Verify task synced to B
    const taskB = pageB.locator('task', { hasText: taskName }).first();
    await expect(taskB).toBeVisible({ timeout: 20000 });
    await expect(taskB).not.toHaveClass(/isDone/);

    // --- Test 1: Mark done on B, verify on A ---
    await taskB.hover();
    const doneBtnB = taskB.locator('done-toggle');
    await doneBtnB.click({ force: true });
    await expect(taskB).toHaveClass(/isDone/);

    // Wait for state persistence before syncing
    await waitForStatePersistence(pageB);

    await syncPageB.triggerSync();
    await waitForSyncComplete(pageB, syncPageB);

    // Sync A to get done state from B
    await syncPageA.triggerSync();
    await waitForSyncComplete(pageA, syncPageA);

    // Wait for state persistence to complete after sync
    await waitForStatePersistence(pageA);

    // Note: We DON'T reload - sync updates NgRx directly
    // Verify task is marked as done on A after sync
    const taskA = pageA.locator('task', { hasText: taskName }).first();
    await expect(taskA).toHaveClass(/isDone/, { timeout: 10000 });

    await contextA.close();
    await contextB.close();
  });
});
