import { db } from './db.js'
import { getActiveMasterKey } from './auth.js'
import { getLogbookKey } from './logbookKeys.js'
import { encryptJson, decryptJson } from './crypto.js'
import { syncLogbook } from './sync.js'
import { PlausibleEvents, trackPlausibleEvent } from './analytics.js'

async function getEncryptionKey(logbookId: string): Promise<ArrayBuffer> {
  const key = await getLogbookKey(logbookId) || getActiveMasterKey()
  if (!key) throw new Error('Encryption key not found. Please log in.')
  return key
}

export async function saveEntryVoiceMemo(options: {
  logbookId: string
  entryId: string
  audioDataUrl: string
  mimeType: string
  durationSec: number
  caption?: string
  transcribed?: boolean
  analyticsContext?: string
}): Promise<string> {
  const {
    logbookId,
    entryId,
    audioDataUrl,
    mimeType,
    durationSec,
    caption = '',
    transcribed = true,
    analyticsContext = 'logbook'
  } = options
  const masterKey = await getEncryptionKey(logbookId)
  const voiceId = window.crypto.randomUUID()
  const voicePayload = {
    audio: audioDataUrl,
    mimeType,
    durationSec,
    caption: caption.trim(),
    transcribed: !!transcribed
  }

  const encrypted = await encryptJson(voicePayload, masterKey)
  const now = new Date().toISOString()

  await db.voiceMemos.put({
    payloadId: voiceId,
    entryId,
    logbookId,
    encryptedData: encrypted.ciphertext,
    iv: encrypted.iv,
    tag: encrypted.tag,
    updatedAt: now
  })

  await db.syncQueue.put({
    action: 'create',
    type: 'voiceMemo',
    payloadId: voiceId,
    logbookId,
    data: JSON.stringify({
      encryptedData: encrypted.ciphertext,
      iv: encrypted.iv,
      tag: encrypted.tag,
      entryId
    }),
    updatedAt: now
  })

  trackPlausibleEvent(PlausibleEvents.VOICE_MEMO_UPLOADED, { context: analyticsContext })
  syncLogbook(logbookId).catch((err) => console.warn('Background sync failed:', err))
  return voiceId
}

export async function deleteEntryVoiceMemo(logbookId: string, voiceId: string): Promise<void> {
  const now = new Date().toISOString()
  await db.voiceMemos.delete(voiceId)
  await db.syncQueue.put({
    action: 'delete',
    type: 'voiceMemo',
    payloadId: voiceId,
    logbookId,
    data: '',
    updatedAt: now
  })
  syncLogbook(logbookId).catch((err) => console.warn('Background sync failed:', err))
}

/** Deletes the newest voice memo for an entry; returns its id or null. */
export async function removeLastVoiceMemoForEntry(
  logbookId: string,
  entryId: string
): Promise<string | null> {
  const memos = await db.voiceMemos.where({ entryId }).toArray()
  if (memos.length === 0) return null
  memos.sort(
    (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
  )
  const lastId = memos[0].payloadId
  await deleteEntryVoiceMemo(logbookId, lastId)
  return lastId
}

/** Updates an existing voice memo payload with a new transcript and sets transcribed: true. */
export async function updateVoiceMemoTranscript(
  logbookId: string,
  voiceId: string,
  transcript: string
): Promise<void> {
  const masterKey = await getEncryptionKey(logbookId)
  const record = await db.voiceMemos.get(voiceId)
  if (!record) throw new Error('Voice memo not found')

  const decrypted = await decryptJson(record.encryptedData, record.iv, record.tag, masterKey)
  if (!decrypted) throw new Error('Failed to decrypt voice memo')

  const manualCaption = decrypted.caption ? String(decrypted.caption).trim() : ''
  const finalCaption = manualCaption
    ? `${manualCaption}\n(Transkript: ${transcript.trim()})`
    : transcript.trim()

  const updatedPayload = {
    ...decrypted,
    caption: finalCaption,
    transcribed: true
  }

  const encrypted = await encryptJson(updatedPayload, masterKey)
  const now = new Date().toISOString()

  await db.voiceMemos.put({
    ...record,
    encryptedData: encrypted.ciphertext,
    iv: encrypted.iv,
    tag: encrypted.tag,
    updatedAt: now
  })

  await db.syncQueue.put({
    action: 'update',
    type: 'voiceMemo',
    payloadId: voiceId,
    logbookId,
    data: JSON.stringify({
      encryptedData: encrypted.ciphertext,
      iv: encrypted.iv,
      tag: encrypted.tag,
      entryId: record.entryId
    }),
    updatedAt: now
  })

  syncLogbook(logbookId).catch((err) => console.warn('Background sync failed:', err))
}
