import { test, expect } from '@playwright/test'
import { loginAsAdmin } from '../helpers/auth.js'
import path from 'path'
import fs from 'fs'

const viewports = {
  desktop: { width: 1280, height: 720 },
  mobile: { width: 375, height: 667 },
}

const publicPages = [
  { name: 'home', path: '/' },
  { name: 'join', path: '/join' },
  { name: 'events', path: '/events' },
  { name: 'coming-soon', path: '/coming-soon' },
  // about and members have no auth middleware — accessible publicly
  { name: 'about', path: '/about' },
  { name: 'members', path: '/members' },
]

const authenticatedPages = [
  { name: 'member-dashboard', path: '/member/dashboard' },
  { name: 'member-profile', path: '/member/profile' },
  { name: 'admin-members', path: '/admin/members' },
  { name: 'admin-events-create', path: '/admin/events/create' },
  // New authenticated pages
  { name: 'member-account', path: '/member/account' },
  { name: 'connections', path: '/connections' },
  { name: 'admin-dashboard', path: '/admin' },
]

// Pages that need mobile coverage captured while authenticated.
// These cover column-collapse breakpoints critical for the page-shell refactor.
// Snapshots use the -mobile-auth suffix to distinguish from the public mobile loop
// (which also captures about-mobile unauthenticated, so names must not collide).
const authenticatedMobilePages = [
  { name: 'about', path: '/about' },
  { name: 'member-dashboard', path: '/member/dashboard' },
  { name: 'member-profile', path: '/member/profile' },
  { name: 'member-account', path: '/member/account' },
  { name: 'connections', path: '/connections' },
]

// Path where the saved admin auth state (cookies) will be stored within a run.
const authStatePath = path.resolve('e2e/.auth/admin.json')

// Wait for fonts and images to load before taking screenshots
async function waitForStable(page) {
  await page.waitForLoadState('networkidle')
  // Wait for web fonts to load
  await page.evaluate(() => document.fonts.ready)
}

// Common mask selectors for dynamic content
function commonMasks(page) {
  return [
    // Dates and times throughout the app
    page.locator('.event-date'),
    page.locator('.event-count'),
    page.locator('time'),
    page.locator('.member-since'),
    // Activity log timestamps
    page.locator('.tl-time'),
    // Admin dashboard stat values (member counts, revenue, etc.)
    page.locator('.stat-val'),
    // Recent member join dates in admin dashboard
    page.locator('.item-date'),
    // Member avatars (ghost images may not load deterministically)
    page.locator('.mc-avatar'),
    page.locator('.cc-avatar'),
    page.locator('.profile-avatar'),
    // Member count text in members page filter bar
    page.locator('.filter-count'),
    // Connections page: filter bar and suggestions vary based on tag/topic
    // state and async fetch ordering. Mask them to keep the structural
    // (PageShell + page-level) regression coverage stable.
    page.locator('.filter-bar'),
    page.locator('.skills-bar'),
    page.locator('.connections-section'),
    page.locator('.loading-state'),
  ]
}

// All visual tests run serially in a single top-level describe block.
//
// Auth is handled with a beforeAll that saves the cookie to disk once. All
// authenticated sub-describes load from that saved state, avoiding repeated
// /api/dev/test-login calls that exhaust the dev server's MongoDB connections.
test.describe('visual regression', () => {
  test.describe.configure({ mode: 'serial' })

  // Log in once before all tests and save the auth cookie.
  // serial mode guarantees this runs before any test in this describe tree.
  test.beforeAll(async ({ browser }) => {
    fs.mkdirSync(path.dirname(authStatePath), { recursive: true })
    const page = await browser.newPage()
    await loginAsAdmin(page)
    await page.context().storageState({ path: authStatePath })
    await page.close()
  })

  // ── Public pages (desktop + mobile) ──────────────────────────────────────
  test.describe('public pages', () => {
    for (const { name, path } of publicPages) {
      for (const [viewportName, viewport] of Object.entries(viewports)) {
        test(`${name} — ${viewportName}`, async ({ page }) => {
          await page.setViewportSize(viewport)
          await page.goto(path)
          await waitForStable(page)

          await expect(page).toHaveScreenshot(`${name}-${viewportName}.png`, {
            maxDiffPixelRatio: 0.01,
            mask: commonMasks(page),
          })
        })
      }
    }
  })

  // ── Authenticated pages (desktop) ─────────────────────────────────────────
  // Loads saved auth cookie — no repeated /api/dev/test-login calls.
  test.describe('authenticated pages', () => {
    test.use({ storageState: authStatePath })

    for (const { name, path } of authenticatedPages) {
      test(`${name} — desktop`, async ({ page }) => {
        await page.setViewportSize(viewports.desktop)
        await page.goto(path)
        await waitForStable(page)

        await expect(page).toHaveScreenshot(`${name}-desktop.png`, {
          maxDiffPixelRatio: 0.01,
          mask: commonMasks(page),
        })
      })
    }

    // members-detail: navigate to the test admin's own profile page.
    // The test admin is created by /api/dev/test-login (email: test-admin@ghostguild.dev,
    // status: active). We fetch their _id from /api/auth/member using the saved cookie.
    // Even if showInDirectory is false, the page renders a stable error or profile shell.
    test('members-detail — desktop', async ({ page }) => {
      await page.setViewportSize(viewports.desktop)
      const response = await page.request.get('/api/auth/member')
      // /api/auth/member returns the member object directly (not nested under a 'member' key)
      const authData = response.ok() ? await response.json() : null
      const memberId = authData?._id || authData?.id
      if (!memberId) {
        // Skip gracefully if we can't retrieve the member ID
        test.skip(true, 'Could not retrieve test admin member ID from /api/auth/member')
        return
      }
      await page.goto(`/members/${memberId}`)
      await waitForStable(page)
      await expect(page).toHaveScreenshot('members-detail-desktop.png', {
        maxDiffPixelRatio: 0.01,
        mask: commonMasks(page),
      })
    })
  })

  // ── Authenticated pages (mobile — column-collapse coverage) ───────────────
  // Loads saved auth cookie — no repeated /api/dev/test-login calls.
  test.describe('authenticated pages (mobile)', () => {
    test.use({ storageState: authStatePath })

    for (const { name, path } of authenticatedMobilePages) {
      test(`${name} — mobile`, async ({ page }) => {
        await page.setViewportSize(viewports.mobile)
        await page.goto(path)
        await waitForStable(page)

        await expect(page).toHaveScreenshot(`${name}-mobile-auth.png`, {
          maxDiffPixelRatio: 0.01,
          mask: commonMasks(page),
        })
      })
    }
  })
})
