/**
 * Chart-of-accounts API routes — accountant-export (wave-15).
 *
 * Mounted at /api/coa in the main route index.
 *
 * GET  /coa/accounts   → { accounts: CoaAccountRow[] }
 * PUT  /coa/accounts   → body { accounts: [...] } → { updated: number }
 * GET  /coa/mappings   → { mappings: CoaMappingRow[] }
 * PUT  /coa/mappings   → body { mappings: [...] } → { updated: number }
 *
 * Read guard: reports:read
 * Write guard: reports:export (editing CoA is an export-config action)
 */
import { Hono } from 'hono'
import { z } from 'zod'
import type { AppEnv } from '../types'
import { authMiddleware } from '../middleware/auth'
import { requirePermission } from '../middleware/guards'
import {
  createDb,
  listCoaAccounts,
  upsertCoaAccounts,
  listCoaMappings,
  upsertCoaMappings,
} from '@zync/db/queries'
import { seedDefaultChartOfAccounts } from '../reports/coa-defaults'

// ── Zod schemas ───────────────────────────────────────────────────────────────

const coaAccountSchema = z.object({
  code: z.string().min(1).max(20),
  name: z.string().min(1).max(100),
  type: z.enum(['asset', 'liability', 'equity', 'revenue', 'expense']),
  form6111Code: z.string().max(20).nullable().optional(),
})

const putAccountsSchema = z.object({
  accounts: z.array(coaAccountSchema).min(1),
})

const coaMappingSchema = z.object({
  sourceKind: z.string().min(1).max(50),
  accountCode: z.string().min(1).max(20),
})

const putMappingsSchema = z.object({
  mappings: z.array(coaMappingSchema).min(1),
})

// ── Router ────────────────────────────────────────────────────────────────────

export const coaRoutes = new Hono<AppEnv>()

coaRoutes.use('*', authMiddleware)

// GET /coa/accounts
coaRoutes.get('/accounts', requirePermission('reports:read'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }
  const tenantId = session.tid
  const db = createDb(c.env)

  let accounts = await listCoaAccounts(db, tenantId)
  if (accounts.length === 0) {
    // Seed defaults on first access
    await seedDefaultChartOfAccounts(c.env, tenantId)
    accounts = await listCoaAccounts(db, tenantId)
  }

  return c.json({ accounts }, 200)
})

// PUT /coa/accounts
coaRoutes.put('/accounts', requirePermission('reports:export'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }
  const tenantId = session.tid

  const body = await c.req.json().catch(() => null)
  const parsed = putAccountsSchema.safeParse(body)
  if (!parsed.success) {
    return c.json({ error: 'Invalid body', details: parsed.error.flatten() }, 400)
  }

  for (const account of parsed.data.accounts) {
    const form6111Code = account.form6111Code?.trim()
    if (form6111Code === '6666') {
      return c.json(
        {
          error:
            "form6111_code '6666' is reserved for computed net profit in Form 6111 and cannot be assigned to an account",
        },
        400,
      )
    }
  }

  const db = createDb(c.env)
  const updated = await upsertCoaAccounts(db, tenantId, parsed.data.accounts)

  return c.json({ updated }, 200)
})

// GET /coa/mappings
coaRoutes.get('/mappings', requirePermission('reports:read'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }
  const tenantId = session.tid
  const db = createDb(c.env)

  let mappings = await listCoaMappings(db, tenantId)
  if (mappings.length === 0) {
    await seedDefaultChartOfAccounts(c.env, tenantId)
    mappings = await listCoaMappings(db, tenantId)
  }

  return c.json({ mappings }, 200)
})

// PUT /coa/mappings
coaRoutes.put('/mappings', requirePermission('reports:export'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }
  const tenantId = session.tid

  const body = await c.req.json().catch(() => null)
  const parsed = putMappingsSchema.safeParse(body)
  if (!parsed.success) {
    return c.json({ error: 'Invalid body', details: parsed.error.flatten() }, 400)
  }

  const db = createDb(c.env)
  const updated = await upsertCoaMappings(db, tenantId, parsed.data.mappings)

  return c.json({ updated }, 200)
})
