/**
 * Admin billing plans API routes — billing-plans-management-ui (P083, wave-9 leaf 1).
 *
 * Mounted at /api/admin/billing-plans in apps/zync-api/src/routes/admin/index.ts.
 *
 * GET    /admin/billing-plans       — list all plans (including archived)
 * POST   /admin/billing-plans       — create a new plan
 * PATCH  /admin/billing-plans/:id   — update an existing plan
 * DELETE /admin/billing-plans/:id   — soft-archive a plan
 *
 * All routes: adminAuthMiddleware + requireAdminSession() + requireAdminPermission.
 * Zod safeParse on every mutating request body.
 * No raw Drizzle — all DB ops via @zync/db/queries.
 */
import { Hono } from 'hono'
import { z } from 'zod'
import { createDb } from '@zync/db/queries'
import {
  listBillingPlans,
  createBillingPlan,
  updateBillingPlan,
  archiveBillingPlan,
  BillingPlanNotFoundError,
  BillingPlanArchivedError,
} from '@zync/db/queries'
import type { AppEnv } from '../../types'
import { adminAuthMiddleware } from '../../middleware/admin-auth'
import { requireAdminSession } from '../../middleware/guards'
import { requireAdminPermission } from '@zync/auth'
import type { AdminSessionPayload } from '@zync/types'

const adminBillingPlansRoutes = new Hono<AppEnv>()

adminBillingPlansRoutes.use('*', adminAuthMiddleware)
adminBillingPlansRoutes.use('*', requireAdminSession())

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

const VALID_TIERS = ['freelancer', 'business', 'enterprise', 'white_label'] as const

const CreatePlanSchema = z.object({
  name: z.string().min(1).max(120),
  tier: z.enum(VALID_TIERS),
  priceMonthly: z.number().int().min(0),
  priceAnnual: z.number().int().min(0),
  features: z.array(z.string().min(1).max(200)).default([]),
  maxUsers: z.number().int().min(1).nullable().optional(),
  maxProjects: z.number().int().min(1).nullable().optional(),
})

const UpdatePlanSchema = z.object({
  name: z.string().min(1).max(120).optional(),
  tier: z.enum(VALID_TIERS).optional(),
  priceMonthly: z.number().int().min(0).optional(),
  priceAnnual: z.number().int().min(0).optional(),
  features: z.array(z.string().min(1).max(200)).optional(),
  maxUsers: z.number().int().min(1).nullable().optional(),
  maxProjects: z.number().int().min(1).nullable().optional(),
})

const UuidParam = z.string().uuid()

// ── GET /admin/billing-plans ─────────────────────────────────────────────────

adminBillingPlansRoutes.get(
  '/',
  requireAdminPermission('admin.billing:read'),
  async (c) => {
    const db = createDb(c.env)
    const plans = await listBillingPlans(db)
    return c.json({ plans })
  },
)

// ── POST /admin/billing-plans ────────────────────────────────────────────────

adminBillingPlansRoutes.post(
  '/',
  requireAdminPermission('admin.billing:write'),
  async (c) => {
    const parsed = CreatePlanSchema.safeParse(await c.req.json())
    if (!parsed.success) {
      return c.json({ error: 'Invalid request', details: parsed.error.flatten() }, 400)
    }

    const session = c.get('session') as AdminSessionPayload
    const db = createDb(c.env)

    const plan = await createBillingPlan(db, session.sub, {
      name: parsed.data.name,
      tier: parsed.data.tier,
      priceMonthly: parsed.data.priceMonthly,
      priceAnnual: parsed.data.priceAnnual,
      features: parsed.data.features,
      maxUsers: parsed.data.maxUsers ?? null,
      maxProjects: parsed.data.maxProjects ?? null,
    })

    return c.json(plan, 201)
  },
)

// ── PATCH /admin/billing-plans/:id ───────────────────────────────────────────

adminBillingPlansRoutes.patch(
  '/:id',
  requireAdminPermission('admin.billing:write'),
  async (c) => {
    const idParsed = UuidParam.safeParse(c.req.param('id'))
    if (!idParsed.success) {
      return c.json({ error: 'Invalid plan ID' }, 400)
    }

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

    const session = c.get('session') as AdminSessionPayload
    const db = createDb(c.env)

    try {
      const plan = await updateBillingPlan(db, session.sub, idParsed.data, parsed.data)
      return c.json(plan, 200)
    } catch (err) {
      if (err instanceof BillingPlanNotFoundError) {
        return c.json({ error: 'Plan not found' }, 404)
      }
      if (err instanceof BillingPlanArchivedError) {
        return c.json({ error: 'Plan is archived and cannot be updated' }, 409)
      }
      throw err
    }
  },
)

// ── DELETE /admin/billing-plans/:id ─────────────────────────────────────────

adminBillingPlansRoutes.delete(
  '/:id',
  requireAdminPermission('admin.billing:write'),
  async (c) => {
    const idParsed = UuidParam.safeParse(c.req.param('id'))
    if (!idParsed.success) {
      return c.json({ error: 'Invalid plan ID' }, 400)
    }

    const session = c.get('session') as AdminSessionPayload
    const db = createDb(c.env)

    try {
      await archiveBillingPlan(db, session.sub, idParsed.data)
      return c.json({ archived: true }, 200)
    } catch (err) {
      if (err instanceof BillingPlanNotFoundError) {
        return c.json({ error: 'Plan not found' }, 404)
      }
      if (err instanceof BillingPlanArchivedError) {
        return c.json({ error: 'Plan is already archived' }, 409)
      }
      throw err
    }
  },
)

export { adminBillingPlansRoutes }
