import { test, expect } from '@playwright/test'
import { API_KEY_HEADER, createTestProject, deleteTestProject } from './helpers'

test.describe('Projects CRUD', () => {
  const cleanup: number[] = []

  test.afterEach(async ({ request }) => {
    for (const id of cleanup) {
      await deleteTestProject(request, id).catch(() => {})
    }
    cleanup.length = 0
  })

  // ── POST /api/projects ──────────────────────────

  test('POST creates project with minimal fields (name only)', async ({ request }) => {
    const { id, res, body } = await createTestProject(request)
    cleanup.push(id)

    expect(res.status()).toBe(201)
    expect(body.project).toBeDefined()
    expect(body.project.name).toContain('e2e-project-')
    expect(body.project.status).toBe('active')
    expect(body.project.slug).toBeTruthy()
    expect(body.project.ticket_prefix).toBeTruthy()
  })

  test('POST creates project with all enhanced fields', async ({ request }) => {
    const { id, res, body } = await createTestProject(request, {
      description: 'Full project for e2e',
      ticket_prefix: 'E2EFULL',
      github_repo: 'test-org/test-repo',
      deadline: Math.floor(Date.now() / 1000) + 86400,
      color: '#3b82f6',
    })
    cleanup.push(id)

    expect(res.status()).toBe(201)
    expect(body.project.description).toBe('Full project for e2e')
    expect(body.project.ticket_prefix).toBe('E2EFULL')
    expect(body.project.github_repo).toBe('test-org/test-repo')
    expect(body.project.deadline).toBeGreaterThan(0)
    expect(body.project.color).toBe('#3b82f6')
  })

  test('POST rejects empty name', async ({ request }) => {
    const res = await request.post('/api/projects', {
      headers: API_KEY_HEADER,
      data: { name: '' },
    })
    expect(res.status()).toBe(400)
  })

  test('POST rejects duplicate slug', async ({ request }) => {
    const { id } = await createTestProject(request, { name: 'Duplicate Test Project' })
    cleanup.push(id)

    const res = await request.post('/api/projects', {
      headers: API_KEY_HEADER,
      data: { name: 'Duplicate Test Project' },
    })
    expect(res.status()).toBe(409)
  })

  // ── GET /api/projects ───────────────────────────

  test('GET list returns projects with enhanced fields', async ({ request }) => {
    const { id } = await createTestProject(request, {
      description: 'Listed project',
      github_repo: 'org/repo',
      color: '#ef4444',
    })
    cleanup.push(id)

    const res = await request.get('/api/projects', { headers: API_KEY_HEADER })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body).toHaveProperty('projects')
    expect(Array.isArray(body.projects)).toBe(true)

    const found = body.projects.find((p: any) => p.id === id)
    expect(found).toBeDefined()
    expect(found.github_repo).toBe('org/repo')
    expect(found.color).toBe('#ef4444')
    expect(typeof found.task_count).toBe('number')
    expect(Array.isArray(found.assigned_agents)).toBe(true)
  })

  test('GET list excludes archived by default', async ({ request }) => {
    const { id } = await createTestProject(request)
    cleanup.push(id)

    // Archive the project
    await request.patch(`/api/projects/${id}`, {
      headers: API_KEY_HEADER,
      data: { status: 'archived' },
    })

    const res = await request.get('/api/projects', { headers: API_KEY_HEADER })
    const body = await res.json()
    const found = body.projects.find((p: any) => p.id === id)
    expect(found).toBeUndefined()

    // But includeArchived=1 should show it
    const resArchived = await request.get('/api/projects?includeArchived=1', { headers: API_KEY_HEADER })
    const bodyArchived = await resArchived.json()
    const foundArchived = bodyArchived.projects.find((p: any) => p.id === id)
    expect(foundArchived).toBeDefined()
    expect(foundArchived.status).toBe('archived')
  })

  // ── GET /api/projects/[id] ──────────────────────

  test('GET single returns enriched project', async ({ request }) => {
    const { id } = await createTestProject(request, {
      description: 'Single project',
      github_repo: 'owner/repo',
      color: '#10b981',
    })
    cleanup.push(id)

    const res = await request.get(`/api/projects/${id}`, { headers: API_KEY_HEADER })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.project).toBeDefined()
    expect(body.project.id).toBe(id)
    expect(body.project.github_repo).toBe('owner/repo')
    expect(body.project.color).toBe('#10b981')
    expect(typeof body.project.task_count).toBe('number')
    expect(Array.isArray(body.project.assigned_agents)).toBe(true)
  })

  test('GET single returns 404 for missing project', async ({ request }) => {
    const res = await request.get('/api/projects/999999', { headers: API_KEY_HEADER })
    expect(res.status()).toBe(404)
  })

  // ── PATCH /api/projects/[id] ────────────────────

  test('PATCH updates basic fields', async ({ request }) => {
    const { id } = await createTestProject(request)
    cleanup.push(id)

    const res = await request.patch(`/api/projects/${id}`, {
      headers: API_KEY_HEADER,
      data: { name: 'Updated Project Name', description: 'Updated description' },
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.project.name).toBe('Updated Project Name')
    expect(body.project.description).toBe('Updated description')
  })

  test('PATCH updates enhanced fields (github_repo, deadline, color)', async ({ request }) => {
    const { id } = await createTestProject(request)
    cleanup.push(id)

    const deadline = Math.floor(Date.now() / 1000) + 172800
    const res = await request.patch(`/api/projects/${id}`, {
      headers: API_KEY_HEADER,
      data: {
        github_repo: 'new-org/new-repo',
        deadline,
        color: '#8b5cf6',
      },
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.project.github_repo).toBe('new-org/new-repo')
    expect(body.project.deadline).toBe(deadline)
    expect(body.project.color).toBe('#8b5cf6')
  })

  test('PATCH can clear optional fields with null', async ({ request }) => {
    const { id } = await createTestProject(request, {
      github_repo: 'will-clear/repo',
      color: '#ef4444',
    })
    cleanup.push(id)

    const res = await request.patch(`/api/projects/${id}`, {
      headers: API_KEY_HEADER,
      data: { github_repo: null, color: null, deadline: null },
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.project.github_repo).toBeNull()
    expect(body.project.color).toBeNull()
    expect(body.project.deadline).toBeNull()
  })

  test('PATCH returns 404 for missing project', async ({ request }) => {
    const res = await request.patch('/api/projects/999999', {
      headers: API_KEY_HEADER,
      data: { name: 'no-op' },
    })
    expect(res.status()).toBe(404)
  })

  test('PATCH rejects archiving default project', async ({ request }) => {
    // Get the general project
    const listRes = await request.get('/api/projects?includeArchived=1', { headers: API_KEY_HEADER })
    const listBody = await listRes.json()
    const general = listBody.projects.find((p: any) => p.slug === 'general')
    expect(general).toBeDefined()

    const res = await request.patch(`/api/projects/${general.id}`, {
      headers: API_KEY_HEADER,
      data: { status: 'archived' },
    })
    expect(res.status()).toBe(400)
  })

  // ── DELETE /api/projects/[id] ───────────────────

  test('DELETE archives project by default', async ({ request }) => {
    const { id } = await createTestProject(request)

    const res = await request.delete(`/api/projects/${id}`, { headers: API_KEY_HEADER })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.mode).toBe('archive')

    // Verify it's archived, not deleted
    const getRes = await request.get(`/api/projects/${id}`, { headers: API_KEY_HEADER })
    expect(getRes.status()).toBe(200)
    const getBody = await getRes.json()
    expect(getBody.project.status).toBe('archived')
  })

  test('DELETE with mode=delete permanently removes project', async ({ request }) => {
    const { id } = await createTestProject(request)

    const res = await request.delete(`/api/projects/${id}?mode=delete`, { headers: API_KEY_HEADER })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.mode).toBe('delete')

    // Verify it's gone
    const getRes = await request.get(`/api/projects/${id}`, { headers: API_KEY_HEADER })
    expect(getRes.status()).toBe(404)
  })

  test('DELETE rejects deleting default project', async ({ request }) => {
    const listRes = await request.get('/api/projects?includeArchived=1', { headers: API_KEY_HEADER })
    const listBody = await listRes.json()
    const general = listBody.projects.find((p: any) => p.slug === 'general')
    expect(general).toBeDefined()

    const res = await request.delete(`/api/projects/${general.id}?mode=delete`, { headers: API_KEY_HEADER })
    expect(res.status()).toBe(400)
  })

  // ── Full lifecycle ───────────────────────────

  test('full lifecycle: create → read → update → archive → reactivate → delete', async ({ request }) => {
    // Create with enhanced fields
    const { id, res: createRes } = await createTestProject(request, {
      description: 'Lifecycle test project',
      github_repo: 'lifecycle/test',
      color: '#f59e0b',
    })
    expect(createRes.status()).toBe(201)

    // Read single
    const readRes = await request.get(`/api/projects/${id}`, { headers: API_KEY_HEADER })
    expect(readRes.status()).toBe(200)
    const readBody = await readRes.json()
    expect(readBody.project.description).toBe('Lifecycle test project')
    expect(readBody.project.github_repo).toBe('lifecycle/test')
    expect(readBody.project.color).toBe('#f59e0b')

    // Update
    const updateRes = await request.patch(`/api/projects/${id}`, {
      headers: API_KEY_HEADER,
      data: { name: 'Updated Lifecycle', github_repo: 'updated/repo', deadline: 1893456000 },
    })
    expect(updateRes.status()).toBe(200)
    const updateBody = await updateRes.json()
    expect(updateBody.project.name).toBe('Updated Lifecycle')
    expect(updateBody.project.github_repo).toBe('updated/repo')
    expect(updateBody.project.deadline).toBe(1893456000)

    // Archive
    const archiveRes = await request.patch(`/api/projects/${id}`, {
      headers: API_KEY_HEADER,
      data: { status: 'archived' },
    })
    expect(archiveRes.status()).toBe(200)
    expect((await archiveRes.json()).project.status).toBe('archived')

    // Reactivate
    const activateRes = await request.patch(`/api/projects/${id}`, {
      headers: API_KEY_HEADER,
      data: { status: 'active' },
    })
    expect(activateRes.status()).toBe(200)
    expect((await activateRes.json()).project.status).toBe('active')

    // Delete permanently
    const deleteRes = await request.delete(`/api/projects/${id}?mode=delete`, { headers: API_KEY_HEADER })
    expect(deleteRes.status()).toBe(200)

    // Confirm gone
    const goneRes = await request.get(`/api/projects/${id}`, { headers: API_KEY_HEADER })
    expect(goneRes.status()).toBe(404)
  })

  // ── Task count ───────────────────────────

  test('project task_count reflects actual tasks', async ({ request }) => {
    const { id } = await createTestProject(request, { ticket_prefix: 'TCNT' })
    cleanup.push(id)

    // Create a task in this project
    const taskRes = await request.post('/api/tasks', {
      headers: API_KEY_HEADER,
      data: { title: `task-count-test-${Date.now()}`, project_id: id },
    })
    expect(taskRes.status()).toBe(201)
    const taskBody = await taskRes.json()
    const taskId = taskBody.task.id

    // Check project task_count
    const getRes = await request.get(`/api/projects/${id}`, { headers: API_KEY_HEADER })
    const getBody = await getRes.json()
    expect(getBody.project.task_count).toBeGreaterThanOrEqual(1)

    // Cleanup task
    await request.delete(`/api/tasks/${taskId}`, { headers: API_KEY_HEADER })
  })
})
