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

const stamp = Date.now()
const testFile = `memory/e2e-mk-${stamp}.md`
const testFile2 = `memory/e2e-mk-linked-${stamp}.md`

test.describe('Memory Knowledge Features', () => {
  // Setup: create test files with wiki-links and schema
  test.beforeAll(async ({ request }) => {
    const file1 = await request.post('/api/memory', {
      headers: API_KEY_HEADER,
      data: {
        action: 'create',
        path: testFile,
        content: [
          '---',
          '_schema:',
          '  type: note',
          '  required: [title, tags]',
          'title: E2E Test Note',
          'tags: [test, e2e]',
          '---',
          `# E2E Note ${stamp}`,
          '',
          `This links to [[e2e-mk-linked-${stamp}]] for testing.`,
          '',
          'Some searchable content: unique-token-' + stamp,
        ].join('\n'),
      },
    })
    expect(file1.status()).toBe(200)

    const file2 = await request.post('/api/memory', {
      headers: API_KEY_HEADER,
      data: {
        action: 'create',
        path: testFile2,
        content: [
          '---',
          'title: Linked Note',
          '---',
          '# Linked Note',
          '',
          `Back-reference to [[e2e-mk-${stamp}]].`,
        ].join('\n'),
      },
    })
    expect(file2.status()).toBe(200)
  })

  // Cleanup
  test.afterAll(async ({ request }) => {
    await request.delete('/api/memory', {
      headers: API_KEY_HEADER,
      data: { action: 'delete', path: testFile },
    })
    await request.delete('/api/memory', {
      headers: API_KEY_HEADER,
      data: { action: 'delete', path: testFile2 },
    })
  })

  // --- Links API ---

  test('GET /api/memory/links returns link graph', async ({ request }) => {
    const res = await request.get('/api/memory/links', {
      headers: API_KEY_HEADER,
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(Array.isArray(body.nodes)).toBe(true)
    expect(body.nodes.length).toBeGreaterThan(0)
    // Each node should have expected shape
    const node = body.nodes[0]
    expect(node).toHaveProperty('path')
    expect(node).toHaveProperty('linkCount')
  })

  test('GET /api/memory/links?file= returns per-file links', async ({ request }) => {
    const res = await request.get(
      `/api/memory/links?file=${encodeURIComponent(testFile)}`,
      { headers: API_KEY_HEADER }
    )
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.file).toBe(testFile)
    expect(Array.isArray(body.wikiLinks)).toBe(true)
    // Should find the wiki-link to the linked file
    const link = body.wikiLinks.find((l: any) => l.target.includes('linked'))
    expect(link).toBeTruthy()
  })

  test('links API requires auth', async ({ request }) => {
    const res = await request.get('/api/memory/links')
    expect(res.status()).toBe(401)
  })

  // --- Health API ---

  test('GET /api/memory/health returns health report', async ({ request }) => {
    const res = await request.get('/api/memory/health', {
      headers: API_KEY_HEADER,
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(typeof body.overallScore).toBe('number')
    expect(body.overallScore).toBeGreaterThanOrEqual(0)
    expect(body.overallScore).toBeLessThanOrEqual(100)
    expect(Array.isArray(body.categories)).toBe(true)
    expect(body.categories.length).toBe(8)
    // Each category has expected shape
    for (const cat of body.categories) {
      expect(cat).toHaveProperty('name')
      expect(cat).toHaveProperty('score')
      expect(typeof cat.score).toBe('number')
    }
  })

  test('health API requires auth', async ({ request }) => {
    const res = await request.get('/api/memory/health')
    expect(res.status()).toBe(401)
  })

  // --- Context API ---

  test('GET /api/memory/context returns context payload', async ({ request }) => {
    const res = await request.get('/api/memory/context', {
      headers: API_KEY_HEADER,
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body).toHaveProperty('fileTree')
    expect(body).toHaveProperty('recentFiles')
    expect(body).toHaveProperty('healthSummary')
    expect(body).toHaveProperty('maintenanceSignals')
    expect(Array.isArray(body.fileTree)).toBe(true)
    expect(Array.isArray(body.recentFiles)).toBe(true)
    expect(Array.isArray(body.maintenanceSignals)).toBe(true)
    expect(typeof body.healthSummary).toBe('object')
  })

  test('context API requires auth', async ({ request }) => {
    const res = await request.get('/api/memory/context')
    expect(res.status()).toBe(401)
  })

  // --- Process API ---

  test('POST /api/memory/process reflect action', async ({ request }) => {
    const res = await request.post('/api/memory/process', {
      headers: API_KEY_HEADER,
      data: { action: 'reflect' },
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.action).toBe('reflect')
    expect(Array.isArray(body.suggestions)).toBe(true)
  })

  test('POST /api/memory/process reweave action', async ({ request }) => {
    const res = await request.post('/api/memory/process', {
      headers: API_KEY_HEADER,
      data: { action: 'reweave' },
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.action).toBe('reweave')
    expect(Array.isArray(body.suggestions)).toBe(true)
  })

  test('POST /api/memory/process generate-moc action', async ({ request }) => {
    const res = await request.post('/api/memory/process', {
      headers: API_KEY_HEADER,
      data: { action: 'generate-moc' },
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.action).toBe('generate-moc')
    expect(Array.isArray(body.groups)).toBe(true)
    expect(typeof body.totalGroups).toBe('number')
    expect(typeof body.totalEntries).toBe('number')
  })

  test('process API rejects invalid action', async ({ request }) => {
    const res = await request.post('/api/memory/process', {
      headers: API_KEY_HEADER,
      data: { action: 'invalid' },
    })
    expect(res.status()).toBe(400)
  })

  test('process API requires auth', async ({ request }) => {
    const res = await request.post('/api/memory/process', {
      data: { action: 'reflect' },
    })
    expect(res.status()).toBe(401)
  })

  // --- Memory content now returns wiki-links and schema ---

  test('GET /api/memory content includes wikiLinks and schema', async ({ request }) => {
    const res = await request.get(
      `/api/memory?action=content&path=${encodeURIComponent(testFile)}`,
      { headers: API_KEY_HEADER }
    )
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.path).toBe(testFile)
    // Wiki-links extracted
    expect(Array.isArray(body.wikiLinks)).toBe(true)
    expect(body.wikiLinks.length).toBeGreaterThan(0)
    // Schema validation result
    expect(body.schema).toBeTruthy()
    expect(body.schema.valid).toBe(true)
    expect(body.schema.errors).toEqual([])
  })

  test('save returns schema warnings for missing required fields', async ({ request }) => {
    const badContent = [
      '---',
      '_schema:',
      '  type: note',
      '  required: [title, tags, missing_field]',
      'title: Present',
      'tags: [a]',
      '---',
      '# Body',
    ].join('\n')

    const res = await request.post('/api/memory', {
      headers: API_KEY_HEADER,
      data: { action: 'save', path: testFile, content: badContent },
    })
    expect(res.status()).toBe(200)
    const body = await res.json()
    expect(body.success).toBe(true)
    expect(Array.isArray(body.schemaWarnings)).toBe(true)
    expect(body.schemaWarnings).toContain('Missing required field: missing_field')
  })
})
