import { suite } from '../lib/context.js'

const MASTER_PASSWORD = 'test-vault-master-2024!'

suite('Vault', { tags: ['vault'] }, (t) => {

  // --- Initialization & Unlock ---

  t.test('initializes vault with master password', { tags: ['init'] }, async () => {
    const res = await t.api.post('/v1/vault/initialize', { masterPassword: MASTER_PASSWORD })
    t.assert.status(res, 201)
    t.assert.contains(res.data.message, 'initialized')
  })

  t.test('rejects re-initialization', { tags: ['init'] }, async () => {
    const res = await t.api.post('/v1/vault/initialize', { masterPassword: 'another-password' })
    t.assert.status(res, 400)
  })

  t.test('reports vault status', { tags: ['status'] }, async () => {
    const res = await t.api.get('/v1/vault/status')
    t.assert.status(res, 200)
    t.assert.equal(res.data.initialized, true)
    t.assert.equal(res.data.unlocked, true)
  })

  t.test('locks vault', { tags: ['lock'] }, async () => {
    const res = await t.api.post('/v1/vault/lock')
    t.assert.status(res, 200)

    const status = await t.api.get('/v1/vault/status')
    t.assert.equal(status.data.unlocked, false)
  })

  t.test('rejects operations when locked', { tags: ['lock'] }, async () => {
    const res = await t.api.get('/v1/vault/categories')
    t.assert.status(res, 403)
    t.assert.contains(res.data.error.message, 'locked')
  })

  t.test('unlocks vault with correct password', { tags: ['lock'] }, async () => {
    const res = await t.api.post('/v1/vault/unlock', { masterPassword: MASTER_PASSWORD })
    t.assert.status(res, 200)

    const status = await t.api.get('/v1/vault/status')
    t.assert.equal(status.data.unlocked, true)
  })

  t.test('rejects unlock with wrong password', { tags: ['lock'] }, async () => {
    await t.api.post('/v1/vault/lock')
    const res = await t.api.post('/v1/vault/unlock', { masterPassword: 'wrong-password' })
    t.assert.status(res, 401)

    // Re-unlock for remaining tests
    await t.api.post('/v1/vault/unlock', { masterPassword: MASTER_PASSWORD })
  })

  // --- Categories ---

  t.test('creates a category', { tags: ['category'] }, async () => {
    const res = await t.api.post('/v1/vault/categories', { name: 'WiFi Passwords', description: 'Store WiFi credentials' })
    t.assert.status(res, 201)
    t.assert.equal(res.data.name, 'WiFi Passwords')
    t.assert.ok(res.data.id)
  })

  t.test('lists accessible categories', { tags: ['category'] }, async () => {
    const res = await t.api.get('/v1/vault/categories')
    t.assert.status(res, 200)
    t.assert.greaterThan(res.data.data.length, 0)
  })

  t.test('gets category detail with accessLevel', { tags: ['category'] }, async () => {
    const list = await t.api.get('/v1/vault/categories')
    const catId = list.data.data[0].id

    const res = await t.api.get(`/v1/vault/categories/${catId}`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.accessLevel, 'admin')
  })

  t.test('updates a category', { tags: ['category'] }, async () => {
    const list = await t.api.get('/v1/vault/categories')
    const catId = list.data.data[0].id

    const res = await t.api.patch(`/v1/vault/categories/${catId}`, { name: 'WiFi & Network' })
    t.assert.status(res, 200)
    t.assert.equal(res.data.name, 'WiFi & Network')
  })

  // --- Entries ---

  t.test('creates an entry with a secret', { tags: ['entry'] }, async () => {
    const list = await t.api.get('/v1/vault/categories')
    const catId = list.data.data[0].id

    const res = await t.api.post(`/v1/vault/categories/${catId}/entries`, {
      name: 'Store WiFi',
      username: 'DemoUser',
      url: 'http://192.168.1.1',
      notes: 'Router admin panel',
      secret: 'supersecretpassword123',
    })
    t.assert.status(res, 201)
    t.assert.equal(res.data.name, 'Store WiFi')
    t.assert.equal(res.data.username, 'DemoUser')
    t.assert.equal(res.data.hasSecret, true)
    // Secret value should NOT be in the response
    t.assert.falsy(res.data.encryptedValue)
    t.assert.falsy(res.data.iv)
    t.assert.falsy(res.data.secret)
  })

  t.test('lists entries without revealing secrets', { tags: ['entry'] }, async () => {
    const cats = await t.api.get('/v1/vault/categories')
    const catId = cats.data.data[0].id

    const res = await t.api.get(`/v1/vault/categories/${catId}/entries`)
    t.assert.status(res, 200)
    t.assert.greaterThan(res.data.data.length, 0)
    t.assert.equal(res.data.data[0].hasSecret, true)
    t.assert.falsy(res.data.data[0].encryptedValue)
  })

  t.test('reveals a secret', { tags: ['entry', 'reveal'] }, async () => {
    const cats = await t.api.get('/v1/vault/categories')
    const catId = cats.data.data[0].id
    const entries = await t.api.get(`/v1/vault/categories/${catId}/entries`)
    const entryId = entries.data.data[0].id

    const res = await t.api.post(`/v1/vault/entries/${entryId}/reveal`)
    t.assert.status(res, 200)
    t.assert.equal(res.data.value, 'supersecretpassword123')
  })

  t.test('updates an entry with new secret', { tags: ['entry'] }, async () => {
    const cats = await t.api.get('/v1/vault/categories')
    const catId = cats.data.data[0].id
    const entries = await t.api.get(`/v1/vault/categories/${catId}/entries`)
    const entryId = entries.data.data[0].id

    const res = await t.api.patch(`/v1/vault/entries/${entryId}`, {
      name: 'Store WiFi (updated)',
      secret: 'newsecret456',
    })
    t.assert.status(res, 200)
    t.assert.equal(res.data.name, 'Store WiFi (updated)')

    // Verify new secret
    const reveal = await t.api.post(`/v1/vault/entries/${entryId}/reveal`)
    t.assert.equal(reveal.data.value, 'newsecret456')
  })

  t.test('creates entry without secret', { tags: ['entry'] }, async () => {
    const cats = await t.api.get('/v1/vault/categories')
    const catId = cats.data.data[0].id

    const res = await t.api.post(`/v1/vault/categories/${catId}/entries`, {
      name: 'Vendor Contact',
      notes: 'Call 555-1234',
    })
    t.assert.status(res, 201)
    t.assert.equal(res.data.hasSecret, false)
  })

  t.test('deletes an entry', { tags: ['entry'] }, async () => {
    const cats = await t.api.get('/v1/vault/categories')
    const catId = cats.data.data[0].id

    // Create one to delete
    const created = await t.api.post(`/v1/vault/categories/${catId}/entries`, {
      name: 'To Delete',
      secret: 'deleteme',
    })

    const res = await t.api.del(`/v1/vault/entries/${created.data.id}`)
    t.assert.status(res, 200)

    const check = await t.api.get(`/v1/vault/entries/${created.data.id}`)
    t.assert.status(check, 404)
  })

  // --- Master Password Change ---

  t.test('changes master password and secrets still work', { tags: ['master'] }, async () => {
    const newMaster = 'new-master-password-2024!'

    const res = await t.api.post('/v1/vault/change-master-password', {
      currentPassword: MASTER_PASSWORD,
      newPassword: newMaster,
    })
    t.assert.status(res, 200)

    // Verify existing secrets still decrypt
    const cats = await t.api.get('/v1/vault/categories')
    const catId = cats.data.data[0].id
    const entries = await t.api.get(`/v1/vault/categories/${catId}/entries`)
    const secretEntry = entries.data.data.find((e: any) => e.hasSecret)
    if (secretEntry) {
      const reveal = await t.api.post(`/v1/vault/entries/${secretEntry.id}/reveal`)
      t.assert.status(reveal, 200)
      t.assert.ok(reveal.data.value)
    }

    // Lock and re-unlock with new password
    await t.api.post('/v1/vault/lock')
    const unlock = await t.api.post('/v1/vault/unlock', { masterPassword: newMaster })
    t.assert.status(unlock, 200)

    // Old password should fail
    await t.api.post('/v1/vault/lock')
    const oldUnlock = await t.api.post('/v1/vault/unlock', { masterPassword: MASTER_PASSWORD })
    t.assert.status(oldUnlock, 401)

    // Re-unlock with new password for cleanup
    await t.api.post('/v1/vault/unlock', { masterPassword: newMaster })
  })

  // --- Delete category ---

  t.test('deletes a category and cascades entries', { tags: ['category'] }, async () => {
    // Create a fresh category with an entry
    const cat = await t.api.post('/v1/vault/categories', { name: 'To Delete Cat' })
    await t.api.post(`/v1/vault/categories/${cat.data.id}/entries`, { name: 'Temp Entry', secret: 'temp' })

    const res = await t.api.del(`/v1/vault/categories/${cat.data.id}`)
    t.assert.status(res, 200)

    const check = await t.api.get(`/v1/vault/categories/${cat.data.id}`)
    t.assert.status(check, 404)
  })
})
