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

function createToken() {
  const header = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' }), 'utf-8').toString('base64');
  const payload = Buffer.from(
    JSON.stringify({ sub: 'e2e', exp: Math.floor(Date.now() / 1000) + 3600 }),
    'utf-8'
  ).toString('base64');
  return `${header}.${payload}.sig`;
}

async function openDashboard(page: import('@playwright/test').Page) {
  const token = createToken();
  await page.goto('/login');
  await page.evaluate((accessToken) => {
    localStorage.setItem('headroom_access_token', accessToken);
    localStorage.setItem('headroom_refresh_token', accessToken);
  }, token);
  await page.goto('/dashboard');
  await page.waitForURL('/dashboard');
}

async function loginThroughForm(page: import('@playwright/test').Page) {
  await page.goto('/login');
  await page.fill('input[type="email"]', 'superuser@headroom.test');
  await page.fill('input[type="password"]', 'password');
  await page.click('button[type="submit"]');
  await page.waitForURL('/dashboard');
}

test.describe('Layout E2E', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/login');
    await page.context().clearCookies();
    await page.evaluate(() => localStorage.clear());
  });

  test('dashboard page has sidebar', async ({ page }) => {
    await openDashboard(page);
    await expect(page.locator('[data-testid="sidebar"]')).toBeVisible();
  });

  test('login redirects to dashboard with sidebar', async ({ page }) => {
    await loginThroughForm(page);
    await expect(page.locator('[data-testid="sidebar"]')).toBeVisible();
  });

  test('sidebar toggle works', async ({ page }) => {
    await openDashboard(page);

    const initial = await page.evaluate(() => document.documentElement.getAttribute('data-sidebar'));
    await page.click('[data-testid="sidebar-toggle"]');

    await expect
      .poll(async () => page.evaluate(() => document.documentElement.getAttribute('data-sidebar')))
      .not.toBe(initial);
  });

  test('theme toggle works', async ({ page }) => {
    await openDashboard(page);

    const before = await page.evaluate(() => localStorage.getItem('headroom_theme') ?? 'light');
    await page.click('[data-testid="theme-toggle"]');

    await expect
      .poll(async () => page.evaluate(() => localStorage.getItem('headroom_theme')))
      .not.toBe(before);
  });

  test('month selector updates period store', async ({ page }) => {
    await openDashboard(page);

    const before = await page.evaluate(() => localStorage.getItem('headroom_selected_period'));
    await page.click('[data-testid="month-selector"] button');
    await page.getByRole('button', { name: 'Next' }).click();

    await expect
      .poll(async () => page.evaluate(() => localStorage.getItem('headroom_selected_period')))
      .not.toBe(before);
  });

  test('breadcrumbs reflect current route', async ({ page }) => {
    await openDashboard(page);
    await expect(page.locator('[data-testid="breadcrumbs"]')).toContainText('Dashboard');
  });

  test('login page has no sidebar', async ({ page }) => {
    await page.goto('/login');
    await expect(page.locator('[data-testid="sidebar"]')).toHaveCount(0);
  });

  test('sidebar hidden by default on mobile', async ({ page }) => {
    await page.setViewportSize({ width: 390, height: 844 });
    await openDashboard(page);

    await expect
      .poll(async () => page.evaluate(() => document.documentElement.getAttribute('data-sidebar')))
      .toBe('hidden');
  });

  test('hamburger shows sidebar on mobile', async ({ page }) => {
    await page.setViewportSize({ width: 390, height: 844 });
    await openDashboard(page);

    await page.click('[data-testid="mobile-hamburger"]');
    await expect
      .poll(async () => page.evaluate(() => document.documentElement.getAttribute('data-sidebar')))
      .toBe('expanded');
  });

  test('sidebar overlays content and closes on backdrop click on mobile', async ({ page }) => {
    await page.setViewportSize({ width: 390, height: 844 });
    await openDashboard(page);

    await page.click('[data-testid="mobile-hamburger"]');
    await expect
      .poll(async () =>
        page.evaluate(() => {
          const main = document.querySelector('[data-testid="layout-main"]');
          if (!main) return null;
          return getComputedStyle(main).marginLeft;
        })
      )
      .toBe('0px');

    await page.evaluate(() => {
      const backdrop = document.querySelector('[data-testid="sidebar-backdrop"]') as HTMLElement | null;
      backdrop?.click();
    });
    await expect
      .poll(async () => page.evaluate(() => document.documentElement.getAttribute('data-sidebar')))
      .toBe('hidden');
  });

  test('all key breakpoints render expected sidebar state', async ({ page }) => {
    const breakpoints: Array<[number, number, 'hidden' | 'collapsed' | 'expanded']> = [
      [320, 700, 'hidden'],
      [768, 900, 'collapsed'],
      [1024, 900, 'collapsed'],
      [1280, 900, 'expanded']
    ];

    for (const [width, height, expected] of breakpoints) {
      await page.setViewportSize({ width, height });
      // Clear localStorage to test default breakpoint behavior
      await page.evaluate(() => localStorage.removeItem('headroom_sidebar_state'));
      await openDashboard(page);
      await expect
        .poll(async () => page.evaluate(() => document.documentElement.getAttribute('data-sidebar')))
        .toBe(expected);
    }
  });

  test('keyboard shortcut toggles sidebar', async ({ page }) => {
    await page.setViewportSize({ width: 1280, height: 900 });
    await openDashboard(page);

    // Wait for sidebar to be fully mounted with event listeners
    await expect(page.locator('[data-testid="sidebar"]')).toBeVisible();
    await page.waitForTimeout(100);

    const before = await page.evaluate(() => document.documentElement.getAttribute('data-sidebar'));
    
    // Focus on the page body to ensure keyboard events are captured
    await page.locator('body').click();
    await page.keyboard.down('Control');
    await page.keyboard.press('\\');
    await page.keyboard.up('Control');

    await expect
      .poll(async () => page.evaluate(() => document.documentElement.getAttribute('data-sidebar')))
      .not.toBe(before);
  });

  test('sidebar is visible after login', async ({ page }) => {
    await loginThroughForm(page);
    
    // Sidebar should be visible
    const sidebar = page.locator('[data-testid="sidebar"]');
    await expect(sidebar).toBeVisible();
    
    // Verify sidebar has content
    await expect(sidebar.locator('text=Dashboard')).toBeVisible();
  });

  test('sidebar toggle button works when collapsed', async ({ page }) => {
    await page.setViewportSize({ width: 1280, height: 900 });
    await openDashboard(page);
    
    // Get initial state
    const sidebar = page.locator('[data-testid="sidebar"]');
    await expect(sidebar).toBeVisible();
    
    // Find and click collapse button (if exists)
    const collapseButton = page.locator('[data-testid="sidebar-toggle"], [aria-label*="toggle"], button').filter({ has: page.locator('svg') }).first();
    
    if (await collapseButton.isVisible().catch(() => false)) {
      // Collapse the sidebar
      await collapseButton.click();
      
      // Wait for collapsed state
      await page.waitForTimeout(300);
      
      // Sidebar should still exist but be in collapsed state
      await expect(sidebar).toBeAttached();
      
      // Click toggle again to expand
      await collapseButton.click();
      await page.waitForTimeout(300);
      
      // Sidebar should be visible again
      await expect(sidebar).toBeVisible();
    }
  });

  test('page refresh after login does not show blank page', async ({ page }) => {
    await loginThroughForm(page);
    
    // Verify we're on dashboard
    await expect(page).toHaveURL('/dashboard');
    await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
    
    // Get the token before refresh
    const tokenBefore = await page.evaluate(() => localStorage.getItem('headroom_access_token'));
    expect(tokenBefore).toBeTruthy();
    
    // Refresh the page
    await page.reload();
    
    // Wait for page to fully load after refresh
    await page.waitForLoadState('networkidle');
    
    // Check what URL we're on (for debugging)
    const currentUrl = page.url();
    
    // We should either be on dashboard (success) or redirected to login (bug)
    // If we're on login, that's the bug being reported
    if (currentUrl.includes('/login')) {
      // Bug: We were redirected to login after refresh
      // Check if token is still there
      const tokenAfter = await page.evaluate(() => localStorage.getItem('headroom_access_token'));
      expect(tokenAfter, 'Token should persist after refresh').toBeTruthy();
      // Fail the test to document the bug
      throw new Error('Bug: User was redirected to login after page refresh despite having valid token');
    }
    
    // If we're still on dashboard, wait for client-side hydration to complete
    await expect(page).toHaveURL('/dashboard');
    
    // Wait for SvelteKit to hydrate the page
    // The page might be SSR'd but needs client-side hydration to show content
    await page.waitForFunction(() => {
      // Check if the page has hydrated by looking for SvelteKit's hydration marker
      return document.querySelector('[data-sveltekit-hydrated]') !== null || 
             document.body.innerHTML.includes('Dashboard');
    }, { timeout: 10000 });
    
    // Now verify content is visible
    await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible({ timeout: 5000 });
    
    // Verify token is still there
    const tokenAfter = await page.evaluate(() => localStorage.getItem('headroom_access_token'));
    expect(tokenAfter).toBe(tokenBefore);
  });

  test('sidebar state persists after page refresh', async ({ page }) => {
    await page.setViewportSize({ width: 1280, height: 900 });
    await openDashboard(page);
    
    // Get initial sidebar state
    const initialState = await page.evaluate(() => 
      document.documentElement.getAttribute('data-sidebar')
    );
    
    // Refresh page
    await page.reload();
    await page.waitForLoadState('networkidle');
    
    // Verify sidebar is still visible
    const sidebar = page.locator('[data-testid="sidebar"]');
    await expect(sidebar).toBeVisible();
    
    // Verify state persisted
    const afterRefresh = await page.evaluate(() => 
      document.documentElement.getAttribute('data-sidebar')
    );
    expect(afterRefresh).toBe(initialState);
  });
});
