import { test, expect, type APIRequestContext, type Page } from '@playwright/test'

const CHILD_NAME = 'RoutineChildModeChild'
const ROUTINE_NAME = 'RoutineChildModeTest'
const ROUTINE_POINTS = 10
const TASK_NAME_1 = 'Brush Teeth'
const TASK_NAME_2 = 'Wash Face'

// ── helpers ───────────────────────────────────────────────────────────────────

async function createChild(request: APIRequestContext, name: string): Promise<string> {
  const pre = await request.get('/api/child/list')
  for (const c of (await pre.json()).children ?? []) {
    if (c.name === name) await request.delete(`/api/child/${c.id}`)
  }
  await request.put('/api/child/add', { data: { name, age: 8 } })
  const list = await request.get('/api/child/list')
  return (await list.json()).children?.find((c: any) => c.name === name)?.id ?? ''
}

async function createRoutine(
  request: APIRequestContext,
  name: string,
  points: number,
): Promise<string> {
  const pre = await request.get('/api/routine/list')
  for (const r of (await pre.json()).routines ?? []) {
    if (r.name === name) await request.delete(`/api/routine/${r.id}`)
  }
  const res = await request.put('/api/routine/add', { data: { name, points } })
  return (await res.json()).routine?.id ?? ''
}

function routineSection(page: Page) {
  return page.locator('.child-list-container').filter({
    has: page.locator('h3', { hasText: 'Routines' }),
  })
}

// ── suite ─────────────────────────────────────────────────────────────────────

test.describe('Routine child-mode flow', () => {
  test.describe.configure({ mode: 'serial' })

  let childId = ''
  let routineId = ''

  test.beforeAll(async ({ request }) => {
    childId = await createChild(request, CHILD_NAME)
    routineId = await createRoutine(request, ROUTINE_NAME, ROUTINE_POINTS)

    await request.put(`/api/routine/${routineId}/item/add`, { data: { name: TASK_NAME_1 } })
    await request.put(`/api/routine/${routineId}/item/add`, { data: { name: TASK_NAME_2 } })
    await request.post(`/api/child/${childId}/assign-routine`, {
      data: { routine_id: routineId },
    })
  })

  test.afterAll(async ({ request }) => {
    if (childId) await request.delete(`/api/child/${childId}`)
    if (routineId) await request.delete(`/api/routine/${routineId}`)
  })

  // Intercept parentAuth so the router treats this session as child-mode (not parent-authenticated).
  test.beforeEach(async ({ page }) => {
    await page.addInitScript(() => {
      const orig = Storage.prototype.getItem
      Storage.prototype.getItem = function (key: string) {
        if (key === 'parentAuth') return null
        return orig.call(this, key)
      }
    })
  })

  // ── 1. Routine section visible ────────────────────────────────────────────

  test('Routine section appears in child view', async ({ page }) => {
    await page.goto(`/child/${childId}`)

    const section = routineSection(page)
    await expect(section).toBeVisible({ timeout: 5000 })
    await expect(section.locator('.item-card').filter({ hasText: ROUTINE_NAME })).toBeVisible()
  })

  // ── 2. Overlay opens on two-click ─────────────────────────────────────────

  test('Clicking routine twice opens overlay with correct header', async ({ page }) => {
    await page.goto(`/child/${childId}`)

    const card = routineSection(page).locator('.item-card').filter({ hasText: ROUTINE_NAME })
    await card.waitFor({ state: 'visible' })

    // First click enters ready state
    await card.click()
    await expect(card).toHaveClass(/item-ready/, { timeout: 3000 })

    // Second click opens overlay
    await card.click()

    const dialog = page.getByRole('dialog')
    await expect(dialog).toBeVisible({ timeout: 3000 })
    await expect(dialog).toContainText('Did you complete')
    await expect(dialog).toContainText(ROUTINE_NAME)
  })

  // ── 3. Task cards inside overlay ──────────────────────────────────────────

  test('Overlay shows task cards for each routine item', async ({ page }) => {
    await page.goto(`/child/${childId}`)

    const card = routineSection(page).locator('.item-card').filter({ hasText: ROUTINE_NAME })
    await card.waitFor({ state: 'visible' })
    await card.click()
    await expect(card).toHaveClass(/item-ready/, { timeout: 3000 })
    await card.click()

    const dialog = page.getByRole('dialog')
    await expect(dialog).toBeVisible({ timeout: 3000 })
    await expect(dialog.getByText(TASK_NAME_1)).toBeVisible()
    await expect(dialog.getByText(TASK_NAME_2)).toBeVisible()
  })

  // ── 4. Closing overlay with No ────────────────────────────────────────────

  test('Clicking No closes the overlay without changing state', async ({ page }) => {
    await page.goto(`/child/${childId}`)

    const card = routineSection(page).locator('.item-card').filter({ hasText: ROUTINE_NAME })
    await card.waitFor({ state: 'visible' })
    await card.click()
    await expect(card).toHaveClass(/item-ready/, { timeout: 3000 })
    await card.click()

    const dialog = page.getByRole('dialog')
    await expect(dialog).toBeVisible({ timeout: 3000 })
    await dialog.getByRole('button', { name: 'No' }).click()

    await expect(dialog).not.toBeVisible({ timeout: 3000 })
    await expect(card.locator('.pending-stamp')).not.toBeVisible()
  })

  // ── 5. Yes! confirms routine → PENDING stamp ──────────────────────────────

  test('Clicking Yes! marks routine as PENDING', async ({ page }) => {
    await page.goto(`/child/${childId}`)

    const card = routineSection(page).locator('.item-card').filter({ hasText: ROUTINE_NAME })
    await card.waitFor({ state: 'visible' })
    await card.click()
    await expect(card).toHaveClass(/item-ready/, { timeout: 3000 })
    await card.click()

    const dialog = page.getByRole('dialog')
    await expect(dialog).toBeVisible({ timeout: 3000 })
    await dialog.getByRole('button', { name: 'Yes!' }).click()

    // Dialog closes
    await expect(dialog).not.toBeVisible({ timeout: 5000 })

    // Reload to pick up the refreshed state
    await page.reload()
    const reloadedCard = routineSection(page)
      .locator('.item-card')
      .filter({ hasText: ROUTINE_NAME })
    await expect(reloadedCard.locator('.pending-stamp')).toBeVisible({ timeout: 5000 })
  })

  // ── 6. Cancel dialog for pending routine ─────────────────────────────────

  test('Clicking a pending routine shows the cancel dialog', async ({ page }) => {
    await page.goto(`/child/${childId}`)

    // Routine should still be pending from the previous test
    const card = routineSection(page).locator('.item-card').filter({ hasText: ROUTINE_NAME })
    await card.waitFor({ state: 'visible' })
    await expect(card.locator('.pending-stamp')).toBeVisible({ timeout: 5000 })

    await card.click()
    await expect(card).toHaveClass(/item-ready/, { timeout: 3000 })
    await card.click()

    const dialog = page.getByRole('dialog')
    await expect(dialog).toBeVisible({ timeout: 3000 })
    await expect(dialog).toContainText('This routine is pending')
  })

  // ── 7. Canceling pending routine removes PENDING stamp ────────────────────

  test('Confirming cancel removes the PENDING stamp', async ({ page }) => {
    await page.goto(`/child/${childId}`)

    const card = routineSection(page).locator('.item-card').filter({ hasText: ROUTINE_NAME })
    await card.waitFor({ state: 'visible' })
    await card.click()
    await expect(card).toHaveClass(/item-ready/, { timeout: 3000 })
    await card.click()

    const dialog = page.getByRole('dialog')
    await expect(dialog).toBeVisible({ timeout: 3000 })
    await expect(dialog).toContainText('This routine is pending')

    // "Yes" cancels the pending confirmation
    await dialog.getByRole('button', { name: 'Yes' }).click()

    await expect(dialog).not.toBeVisible({ timeout: 5000 })

    await page.reload()
    const reloadedCard = routineSection(page)
      .locator('.item-card')
      .filter({ hasText: ROUTINE_NAME })
    await expect(reloadedCard.locator('.pending-stamp')).not.toBeVisible({ timeout: 5000 })
  })
})
