import { Hono } from 'hono'
import { z } from 'zod'
import { TenantTier } from '@zync/types'
import type { AppEnv } from '../../types'
import { authMiddleware } from '../../middleware/auth'
import { requirePermission, requireTier } from '../../middleware/guards'
import {
  getTenantProfitability,
  getProjectProfitability,
  getCustomerProfitability,
} from '@zync/db/queries'

const profitabilityRoutes = new Hono<AppEnv>()

profitabilityRoutes.use('*', authMiddleware)
profitabilityRoutes.use('*', requireTier(TenantTier.BUSINESS))
profitabilityRoutes.use('*', requirePermission('reports:read'))

const profitabilityQuerySchema = z.object({
  from: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  to: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  start: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  end: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
  format: z.enum(['json', 'csv']).optional(),
  scope: z.enum(['project', 'customer']).optional(),
})

function defaultDateRange(): { from: string; to: string } {
  const now = new Date()
  const to = now.toISOString().slice(0, 10)
  const from = new Date(now.getFullYear(), now.getMonth() - 11, 1).toISOString().slice(0, 10)
  return { from, to }
}

function ensureAdminRole(session: { role?: string }) {
  return session.role === 'OWNER' || session.role === 'ADMIN'
}

function csvEscape(value: string): string {
  if (/[",\n]/.test(value)) {
    return `"${value.replace(/"/g, '""')}"`
  }
  return value
}

profitabilityRoutes.get('/', async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'No tenant context' }, 403)
  }
  if (!ensureAdminRole(session)) {
    return c.json({ error: 'Forbidden — OWNER or ADMIN only' }, 403)
  }

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

  const defaults = defaultDateRange()
  const from = parsed.data.from ?? parsed.data.start ?? defaults.from
  const to = parsed.data.to ?? parsed.data.end ?? defaults.to
  const db = c.get('db')
  const report = await getTenantProfitability(db, session.tid, from, to)

  if (parsed.data.format === 'csv') {
    const scope = parsed.data.scope === 'customer' ? 'customer' : 'project'
    const rows = scope === 'customer' ? report.byCustomer : report.byProject
    const body = [
      ['Name', 'Revenue', 'Cost', 'Profit', 'Margin %'].join(','),
      ...rows.map((row) =>
        [
          csvEscape(row.name),
          row.revenue,
          row.cost,
          row.profit,
          row.margin ?? '',
        ].join(','),
      ),
      ['Totals', report.summary.revenue, report.summary.cost, report.summary.profit, report.summary.margin ?? ''].join(','),
    ].join('\n')

    c.header('Content-Type', 'text/csv; charset=utf-8')
    c.header(
      'Content-Disposition',
      `attachment; filename="profitability-${scope}-${from}_${to}.csv"`,
    )
    return c.body(body)
  }

  return c.json(report)
})

profitabilityRoutes.get('/projects/:id', async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'No tenant context' }, 403)
  }
  if (!ensureAdminRole(session)) {
    return c.json({ error: 'Forbidden — OWNER or ADMIN only' }, 403)
  }

  const result = await getProjectProfitability(c.get('db'), session.tid, c.req.param('id'))
  if (!result) return c.json({ error: 'Project not found' }, 404)
  return c.json(result)
})

profitabilityRoutes.get('/customers/:id', async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'No tenant context' }, 403)
  }
  if (!ensureAdminRole(session)) {
    return c.json({ error: 'Forbidden — OWNER or ADMIN only' }, 403)
  }

  const result = await getCustomerProfitability(c.get('db'), session.tid, c.req.param('id'))
  if (!result) return c.json({ error: 'Customer not found' }, 404)
  return c.json(result)
})

profitabilityRoutes.get('/clients/:id', async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'No tenant context' }, 403)
  }
  if (!ensureAdminRole(session)) {
    return c.json({ error: 'Forbidden — OWNER or ADMIN only' }, 403)
  }

  const result = await getCustomerProfitability(c.get('db'), session.tid, c.req.param('id'))
  if (!result) return c.json({ error: 'Customer not found' }, 404)
  return c.json(result)
})

export { profitabilityRoutes }
