// spec: e2e/plans/user-profile.plan.md

import { test, expect, type APIRequestContext } from '@playwright/test'
import path from 'path'
import { fileURLToPath } from 'url'
import { E2E_EMAIL, E2E_FIRST_NAME } from '../../e2e-constants'

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const TEST_IMAGE = path.join(__dirname, '../../.resources/crown.png')

const BACKEND = 'http://localhost:5000'

interface ProfileData {
  first_name: string
  last_name: string
  image_id: string | null
}

async function getProfile(request: APIRequestContext): Promise<ProfileData> {
  const res = await request.get(`${BACKEND}/user/profile`)
  const data = await res.json()
  return { first_name: data.first_name, last_name: data.last_name, image_id: data.image_id ?? null }
}

async function restoreProfile(request: APIRequestContext, profile: ProfileData): Promise<void> {
  await request.put(`${BACKEND}/user/profile`, {
    data: {
      first_name: profile.first_name,
      last_name: profile.last_name,
      image_id: profile.image_id,
    },
  })
}

test.describe('User Profile – editing', () => {
  test.describe.configure({ mode: 'serial' })

  let originalProfile: ProfileData

  test.beforeEach(async ({ request }) => {
    originalProfile = await getProfile(request)
  })

  test.afterEach(async ({ request }) => {
    await restoreProfile(request, originalProfile)
  })

  test('Profile page loads with correct data', async ({ page }) => {
    await page.goto('/parent/profile')

    await expect(page.getByRole('heading', { name: 'User Profile' })).toBeVisible()
    await expect(page.getByLabel('First Name')).toHaveValue(E2E_FIRST_NAME)
    await expect(page.getByLabel('Last Name')).toHaveValue('Tester')
    await expect(page.getByLabel('Email Address')).toHaveValue(E2E_EMAIL)
    await expect(page.getByLabel('Email Address')).toBeDisabled()
  })

  test('Back button navigates back', async ({ page }) => {
    await page.goto('/parent')
    // Navigate in-app via the profile dropdown so Vue Router has a real history entry.
    await page.getByRole('button', { name: 'Parent menu' }).click()
    await page.getByRole('menuitem', { name: 'Profile' }).click()
    await expect(page).toHaveURL('/parent/profile')

    await page.getByRole('button', { name: 'Cancel' }).click()

    await expect(page).toHaveURL('/parent')
  })

  test('Save is disabled when form is clean (not dirty)', async ({ page }) => {
    await page.goto('/parent/profile')

    await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
  })

  test('Save is disabled when First Name is empty', async ({ page }) => {
    await page.goto('/parent/profile')

    await page.getByLabel('First Name').fill('')
    await page.getByLabel('First Name').blur()

    await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
  })

  test('Save is disabled when Last Name is empty', async ({ page }) => {
    await page.goto('/parent/profile')

    await page.getByLabel('Last Name').fill('')
    await page.getByLabel('Last Name').blur()

    await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
  })

  test('Save is disabled when both name fields are empty', async ({ page }) => {
    await page.goto('/parent/profile')

    await page.getByLabel('First Name').fill('')
    await page.getByLabel('Last Name').fill('')

    await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
  })

  test('Save enables when a name is changed', async ({ page }) => {
    await page.goto('/parent/profile')

    await page.getByLabel('First Name').fill('UpdatedE2E')

    await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled()
  })

  test('Save persists name changes and shows confirmation modal', async ({ page }) => {
    await page.goto('/parent/profile')

    await page.getByLabel('First Name').fill('UpdatedE2E')
    await page.getByLabel('Last Name').fill('UpdatedTester')
    await page.getByRole('button', { name: 'Save' }).click()

    const dialog = page.locator('.modal-dialog')
    await expect(dialog.locator('.modal-title', { hasText: 'Profile Updated' })).toBeVisible()
    await expect(dialog.getByText('Your profile was updated successfully.')).toBeVisible()
    await dialog.getByRole('button', { name: 'OK' }).click()

    // OK navigates back; go back to profile to verify persistence
    await page.goto('/parent/profile')
    await expect(page.getByLabel('First Name')).toHaveValue('UpdatedE2E')
    await expect(page.getByLabel('Last Name')).toHaveValue('UpdatedTester')
  })

  test('Cancel discards unsaved changes', async ({ page }) => {
    await page.goto('/parent/profile')

    await page.getByLabel('First Name').fill('Discarded')

    await page.getByRole('button', { name: 'Cancel' }).click()

    // Navigate back to verify no changes were saved
    await page.goto('/parent/profile')
    await expect(page.getByLabel('First Name')).toHaveValue(E2E_FIRST_NAME)
  })

  test('Email field is read-only', async ({ page }) => {
    await page.goto('/parent/profile')

    const emailInput = page.locator('#email')
    await expect(emailInput).toBeDisabled()
    await expect(emailInput).toHaveValue(E2E_EMAIL)
  })

  test('Change profile image (built-in)', async ({ page }) => {
    await page.goto('/parent/profile')

    // Wait for images to load
    await page.waitForSelector('.selectable-image')

    // Pick the second image in the list (index 1), regardless of which is selected
    const images = page.locator('.selectable-image')
    const count = await images.count()
    expect(count).toBeGreaterThan(1)

    // Find first image that is NOT currently selected
    let targetIndex = -1
    for (let i = 0; i < count; i++) {
      const cls = await images.nth(i).getAttribute('class')
      if (!cls?.includes('selected')) {
        targetIndex = i
        break
      }
    }
    expect(targetIndex).toBeGreaterThanOrEqual(0)

    await images.nth(targetIndex).click()

    // Confirm it is now selected
    await expect(images.nth(targetIndex)).toHaveClass(/selected/)

    // Save
    await page.getByRole('button', { name: 'Save' }).click()
    await expect(
      page.locator('.modal-dialog .modal-title', { hasText: 'Profile Updated' }),
    ).toBeVisible()
    await page.locator('.modal-dialog').getByRole('button', { name: 'OK' }).click()

    // Re-visit and confirm selection persists
    await page.goto('/parent/profile')
    await page.waitForSelector('.selectable-image')
    const selectedSrc = await page.locator('.selectable-image.selected').getAttribute('src')
    expect(selectedSrc).toBeTruthy()
    // The URL will differ after a new load (Object URL vs cached), so verify via API
    const profile = await getProfile(page.request)
    expect(profile.image_id).toBeTruthy()
  })

  test('Upload a custom profile image', async ({ page }) => {
    await page.goto('/parent/profile')

    await page.waitForSelector('.selectable-image')

    const fileChooserPromise = page.waitForEvent('filechooser')
    await page.getByRole('button', { name: 'Add from device' }).click()
    const fileChooser = await fileChooserPromise
    await fileChooser.setFiles(TEST_IMAGE)

    // The uploaded image appears first in the list and is selected
    await expect(page.locator('.selectable-image').first()).toHaveClass(/selected/)

    // Save is now enabled
    await expect(page.getByRole('button', { name: 'Save' })).toBeEnabled()
    await page.getByRole('button', { name: 'Save' }).click()

    await expect(
      page.locator('.modal-dialog .modal-title', { hasText: 'Profile Updated' }),
    ).toBeVisible()
    await page.locator('.modal-dialog').getByRole('button', { name: 'OK' }).click()
  })

  test('Change Password shows email-sent modal', async ({ page }) => {
    await page.goto('/parent/profile')

    await page.getByRole('button', { name: 'Change Password' }).click()

    // Modal appears
    const dialog = page.locator('.modal-dialog')
    await expect(dialog.locator('.modal-title', { hasText: 'Change Password' })).toBeVisible()

    // Eventually becomes the confirmed state
    await expect(
      dialog.locator('.modal-title', { hasText: 'Password Change Email Sent' }),
    ).toBeVisible({
      timeout: 10000,
    })
    await expect(dialog.locator('.modal-message')).toContainText(/password change link/i)

    await dialog.getByRole('button', { name: 'OK' }).click()

    // Modal dismissed, back on the profile page
    await expect(page.getByRole('heading', { name: 'User Profile' })).toBeVisible()
  })
})
