import type { FastifyPluginAsync } from 'fastify'
import {
  PaginationSchema,
  InvoiceCreateSchema,
  PaymentApplicationSchema,
  InvoiceVoidSchema,
  InvoiceWriteOffSchema,
} from '@lunarfront/shared/schemas'
import { InvoiceService } from '../../services/invoice.service.js'
import { AccountBalanceService } from '../../services/account-balance.service.js'

export const invoiceRoutes: FastifyPluginAsync = async (app) => {
  // --- Invoices ---

  app.get('/invoices', { preHandler: [app.authenticate, app.requirePermission('accounting.view')] }, async (request, reply) => {
    const query = request.query as Record<string, string | undefined>
    const params = PaginationSchema.parse(query)
    const filters = {
      accountId: query.accountId,
      status: query.status,
      dateFrom: query.dateFrom,
      dateTo: query.dateTo,
    }
    const result = await InvoiceService.list(app.db, params, filters)
    return reply.send(result)
  })

  app.get('/invoices/:id', { preHandler: [app.authenticate, app.requirePermission('accounting.view')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const invoice = await InvoiceService.getById(app.db, id)
    if (!invoice) return reply.status(404).send({ error: { message: 'Invoice not found', statusCode: 404 } })
    return reply.send(invoice)
  })

  app.post('/invoices', { preHandler: [app.authenticate, app.requirePermission('accounting.edit')] }, async (request, reply) => {
    const parsed = InvoiceCreateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const invoice = await InvoiceService.create(app.db, parsed.data, request.user.id)
    request.log.info({ invoiceId: invoice.id, invoiceNumber: invoice.invoiceNumber }, 'Invoice created')
    return reply.status(201).send(invoice)
  })

  app.post('/invoices/:id/send', { preHandler: [app.authenticate, app.requirePermission('accounting.edit')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const invoice = await InvoiceService.send(app.db, id)
    request.log.info({ invoiceId: id }, 'Invoice sent')
    return reply.send(invoice)
  })

  app.post('/invoices/:id/apply-payment', { preHandler: [app.authenticate, app.requirePermission('accounting.edit')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = PaymentApplicationSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const application = await InvoiceService.applyPayment(app.db, id, parsed.data, request.user.id)
    request.log.info({ invoiceId: id, amount: parsed.data.amount }, 'Payment applied')
    return reply.send(application)
  })

  app.post('/invoices/:id/void', { preHandler: [app.authenticate, app.requirePermission('accounting.admin')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = InvoiceVoidSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const invoice = await InvoiceService.void(app.db, id, parsed.data.reason, request.user.id)
    request.log.info({ invoiceId: id, reason: parsed.data.reason }, 'Invoice voided')
    return reply.send(invoice)
  })

  app.post('/invoices/:id/write-off', { preHandler: [app.authenticate, app.requirePermission('accounting.admin')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = InvoiceWriteOffSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const invoice = await InvoiceService.writeOff(app.db, id, parsed.data.reason, request.user.id)
    request.log.info({ invoiceId: id, reason: parsed.data.reason }, 'Invoice written off')
    return reply.send(invoice)
  })

  // --- Account Invoices & Balance ---

  app.get('/accounts/:id/invoices', { preHandler: [app.authenticate, app.requirePermission('accounting.view')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const query = request.query as Record<string, string | undefined>
    const params = PaginationSchema.parse(query)
    const result = await InvoiceService.listByAccount(app.db, id, params)
    return reply.send(result)
  })

  app.get('/accounts/:id/balance', { preHandler: [app.authenticate, app.requirePermission('accounting.view')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const balance = await AccountBalanceService.getBalance(app.db, id)
    return reply.send(balance)
  })

  // --- Export ---

  app.get('/invoices/export', { preHandler: [app.authenticate, app.requirePermission('accounting.view')] }, async (request, reply) => {
    const query = request.query as Record<string, string | undefined>
    const csv = await InvoiceService.exportCSV(app.db, {
      dateFrom: query.dateFrom,
      dateTo: query.dateTo,
    })
    return reply
      .header('Content-Type', 'text/csv')
      .header('Content-Disposition', `attachment; filename="invoices-${new Date().toISOString().slice(0, 10)}.csv"`)
      .send(csv)
  })

  // --- AR Aging ---

  app.get('/invoices/aging', { preHandler: [app.authenticate, app.requirePermission('accounting.view')] }, async (request, reply) => {
    const report = await InvoiceService.getAgingReport(app.db)
    return reply.send(report)
  })

  // --- Outstanding Accounts ---

  app.get('/accounts/outstanding', { preHandler: [app.authenticate, app.requirePermission('accounting.view')] }, async (request, reply) => {
    const query = request.query as Record<string, string | undefined>
    const params = PaginationSchema.parse(query)
    const result = await AccountBalanceService.getOutstandingAccounts(app.db, params)
    return reply.send(result)
  })
}
