/**
 * POST /api/ai-assistant/categorize-expense — OCR expense categorization.
 *
 * Business tier. No RAG, no session. Single callAI call with `expense_ocr` use case.
 * Returns { category, isPersonal, taxHint, confidence }.
 * On AI parse failure returns safe defaults with confidence: 0.
 */
import { Hono } from 'hono'
import { z } from 'zod'
import { createDb } from '@zync/db/queries'
import type { AppEnv } from '../../types'
import type { SessionPayload } from '@zync/types'
import { authMiddleware } from '../../middleware/auth'
import { requireTier } from '../../middleware/guards'
import { TenantTier } from '@zync/types'
import { callAI } from '@zync/ai'

const categorizeRouter = new Hono<AppEnv>()

categorizeRouter.use('*', authMiddleware)
categorizeRouter.use('*', requireTier(TenantTier.BUSINESS))

const body = z.object({
  extractedText: z.string().min(1).max(20000),
  existingCategories: z.array(z.string()),
})

interface CategorizeExpenseResult {
  category: string
  isPersonal: boolean
  taxHint: string
  confidence: number
}

const SAFE_DEFAULT: CategorizeExpenseResult = {
  category: 'Uncategorized',
  isPersonal: false,
  taxHint: '',
  confidence: 0,
}

categorizeRouter.post('/', async (c) => {
  const session = c.get('session') as SessionPayload
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

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

  const { extractedText, existingCategories } = parsed.data

  const categoriesStr =
    existingCategories.length > 0
      ? `Existing categories (prefer one if it fits): ${existingCategories.join(', ')}.`
      : 'No existing categories defined.'

  const prompt = `You are an expense categorization assistant. Analyze the following extracted text from an expense receipt or document and return a JSON object with exactly these fields:
- category: string (the best category name; prefer an existing one if it fits)
- isPersonal: boolean (true if this is a personal expense, false if business)
- taxHint: string (brief tax advice, e.g. "Deductible as office supplies" or "Not tax deductible")
- confidence: number (0 to 1, your confidence in the categorization)

${categoriesStr}

Extracted text:
${extractedText}

Respond with ONLY valid JSON, no explanation.`

  const db = createDb(c.env)

  try {
    const response = await callAI(
      { db, env: c.env },
      {
        tenantId: session.tid,
        userId: session.sub,
        useCase: 'expense_ocr',
        tier: session.tier,
        messages: [{ role: 'user', content: prompt }],
        maxTokens: 256,
      },
    )

    // Parse JSON from response
    const raw = response.content.trim()
    // Strip markdown code fences if present
    const jsonStr = raw.startsWith('```') ? raw.replace(/^```[a-z]*\n?/, '').replace(/\n?```$/, '') : raw

    try {
      const data = JSON.parse(jsonStr) as Partial<CategorizeExpenseResult>
      const result: CategorizeExpenseResult = {
        category:
          typeof data.category === 'string' && data.category.length > 0
            ? data.category
            : SAFE_DEFAULT.category,
        isPersonal: typeof data.isPersonal === 'boolean' ? data.isPersonal : false,
        taxHint: typeof data.taxHint === 'string' ? data.taxHint : '',
        confidence:
          typeof data.confidence === 'number' && data.confidence >= 0 && data.confidence <= 1
            ? data.confidence
            : 0,
      }
      return c.json(result)
    } catch {
      return c.json(SAFE_DEFAULT)
    }
  } catch (err) {
    console.error('[categorize-expense] AI call failed:', err)
    return c.json(SAFE_DEFAULT)
  }
})

export { categorizeRouter }
