import type { FastifyPluginAsync } from 'fastify'
import {
  PaginationSchema,
  RepairTicketCreateSchema,
  RepairTicketUpdateSchema,
  RepairTicketStatusUpdateSchema,
  RepairLineItemCreateSchema,
  RepairLineItemUpdateSchema,
  RepairBatchCreateSchema,
  RepairBatchUpdateSchema,
  RepairBatchStatusUpdateSchema,
  RepairNoteCreateSchema,
  RepairServiceTemplateCreateSchema,
  RepairServiceTemplateUpdateSchema,
} from '@lunarfront/shared/schemas'
import { eq } from 'drizzle-orm'
import { z } from 'zod'
import { RepairTicketService, RepairLineItemService, RepairBatchService, RepairNoteService, RepairServiceTemplateService } from '../../services/repair.service.js'
import { accounts } from '../../db/schema/accounts.js'
import { companies } from '../../db/schema/stores.js'
import { EmailService } from '../../services/email.service.js'
import { renderEstimateEmailHtml, renderEstimateEmailText } from '../../utils/email-templates.js'

export const repairRoutes: FastifyPluginAsync = async (app) => {
  // --- Repair Tickets ---

  app.post('/repair-tickets', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => {
    const parsed = RepairTicketCreateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const ticket = await RepairTicketService.create(app.db, parsed.data)
    return reply.status(201).send(ticket)
  })

  app.get('/repair-tickets/ready', { preHandler: [app.authenticate, app.requirePermission('pos.view')] }, async (request, reply) => {
    const query = request.query as Record<string, string | undefined>
    const params = PaginationSchema.parse(query)
    const result = await RepairTicketService.listReadyForPickup(app.db, params)
    return reply.send(result)
  })

  app.get('/repair-tickets', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
    const query = request.query as Record<string, string | undefined>
    const params = PaginationSchema.parse(query)

    const filters = {
      status: query.status?.split(',').filter(Boolean),
      conditionIn: query.conditionIn?.split(',').filter(Boolean),
      isBatch: query.isBatch === 'true' ? true : query.isBatch === 'false' ? false : undefined,
      batchNumber: query.batchNumber,
      intakeDateFrom: query.intakeDateFrom,
      intakeDateTo: query.intakeDateTo,
      promisedDateFrom: query.promisedDateFrom,
      promisedDateTo: query.promisedDateTo,
      completedDateFrom: query.completedDateFrom,
      completedDateTo: query.completedDateTo,
    }

    const result = await RepairTicketService.list(app.db, params, filters)
    return reply.send(result)
  })

  app.get('/repair-tickets/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const ticket = await RepairTicketService.getById(app.db, id)
    if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })

    let customerEmail: string | null = null
    if (ticket.accountId) {
      const [acct] = await app.db.select({ email: accounts.email }).from(accounts).where(eq(accounts.id, ticket.accountId)).limit(1)
      customerEmail = acct?.email ?? null
    }

    return reply.send({ ...ticket, customerEmail })
  })

  app.patch('/repair-tickets/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = RepairTicketUpdateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const ticket = await RepairTicketService.update(app.db, id, parsed.data)
    if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })
    return reply.send(ticket)
  })

  app.post('/repair-tickets/:id/status', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = RepairTicketStatusUpdateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const ticket = await RepairTicketService.updateStatus(app.db, id, parsed.data.status)
    if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })
    return reply.send(ticket)
  })

  app.post('/repair-tickets/:id/email-estimate', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = z.object({ email: z.string().email() }).safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Valid email is required', statusCode: 400 } })
    }

    // Rate limit: max 5 emails per ticket per hour
    const rateKey = `email-estimate:${id}`
    const count = await app.redis.incr(rateKey)
    if (count === 1) await app.redis.expire(rateKey, 3600)
    if (count > 5) {
      return reply.status(429).send({ error: { message: 'Too many emails for this estimate. Try again later.', statusCode: 429 } })
    }

    const ticket = await RepairTicketService.getById(app.db, id)
    if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })

    const lineItemsResult = await RepairLineItemService.listByTicket(app.db, id, { page: 1, limit: 500 })
    const [company] = await app.db.select().from(companies).limit(1)
    if (!company) return reply.status(500).send({ error: { message: 'Store not configured', statusCode: 500 } })

    const html = renderEstimateEmailHtml(ticket as any, lineItemsResult.data as any[], { name: company.name, phone: company.phone, email: company.email, address: company.address as any })
    const text = renderEstimateEmailText(ticket as any, lineItemsResult.data as any[], { name: company.name, phone: company.phone, email: company.email, address: company.address as any })

    await EmailService.send(app.db, {
      to: parsed.data.email,
      subject: `Repair Estimate — Ticket #${ticket.ticketNumber}`,
      html,
      text,
    })

    request.log.info({ ticketId: id, email: parsed.data.email, userId: request.user.id }, 'Estimate email sent')
    return reply.send({ message: 'Estimate sent', sentTo: parsed.data.email })
  })

  app.delete('/repair-tickets/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const ticket = await RepairTicketService.delete(app.db, id)
    if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })
    return reply.send(ticket)
  })

  // --- Repair Line Items ---

  app.post('/repair-tickets/:ticketId/line-items', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => {
    const { ticketId } = request.params as { ticketId: string }
    const parsed = RepairLineItemCreateSchema.safeParse({ ...(request.body as object), repairTicketId: ticketId })
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const item = await RepairLineItemService.create(app.db, parsed.data)
    return reply.status(201).send(item)
  })

  app.get('/repair-tickets/:ticketId/line-items', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
    const { ticketId } = request.params as { ticketId: string }
    const params = PaginationSchema.parse(request.query)
    const result = await RepairLineItemService.listByTicket(app.db, ticketId, params)
    return reply.send(result)
  })

  app.patch('/repair-line-items/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = RepairLineItemUpdateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const item = await RepairLineItemService.update(app.db, id, parsed.data)
    if (!item) return reply.status(404).send({ error: { message: 'Line item not found', statusCode: 404 } })
    return reply.send(item)
  })

  app.delete('/repair-line-items/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const item = await RepairLineItemService.delete(app.db, id)
    if (!item) return reply.status(404).send({ error: { message: 'Line item not found', statusCode: 404 } })
    return reply.send(item)
  })

  // --- Repair Batches ---

  app.post('/repair-batches', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => {
    const parsed = RepairBatchCreateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const batch = await RepairBatchService.create(app.db, parsed.data)
    return reply.status(201).send(batch)
  })

  app.get('/repair-batches', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
    const params = PaginationSchema.parse(request.query)
    const result = await RepairBatchService.list(app.db, params)
    return reply.send(result)
  })

  app.get('/repair-batches/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const batch = await RepairBatchService.getById(app.db, id)
    if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
    return reply.send(batch)
  })

  app.patch('/repair-batches/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = RepairBatchUpdateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const batch = await RepairBatchService.update(app.db, id, parsed.data)
    if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
    return reply.send(batch)
  })

  app.post('/repair-batches/:id/status', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = RepairBatchStatusUpdateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const batch = await RepairBatchService.updateStatus(app.db, id, parsed.data.status)
    if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
    return reply.send(batch)
  })

  app.post('/repair-batches/:id/approve', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const batch = await RepairBatchService.approve(app.db, id, request.user.id)
    if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
    return reply.send(batch)
  })

  app.post('/repair-batches/:id/reject', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const batch = await RepairBatchService.reject(app.db, id)
    if (!batch) return reply.status(404).send({ error: { message: 'Repair batch not found', statusCode: 404 } })
    return reply.send(batch)
  })

  app.get('/repair-batches/:batchId/tickets', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
    const { batchId } = request.params as { batchId: string }
    const params = PaginationSchema.parse(request.query)
    const result = await RepairTicketService.listByBatch(app.db, batchId, params)
    return reply.send(result)
  })

  // --- Repair Notes ---

  app.post('/repair-tickets/:ticketId/notes', { preHandler: [app.authenticate, app.requirePermission('repairs.edit')] }, async (request, reply) => {
    const { ticketId } = request.params as { ticketId: string }
    const parsed = RepairNoteCreateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const ticket = await RepairTicketService.getById(app.db, ticketId)
    if (!ticket) return reply.status(404).send({ error: { message: 'Repair ticket not found', statusCode: 404 } })

    // Look up author name from users table
    const { users } = await import('../../db/schema/users.js')
    const { eq } = await import('drizzle-orm')
    const [author] = await app.db.select({ firstName: users.firstName, lastName: users.lastName }).from(users).where(eq(users.id, request.user.id)).limit(1)
    const authorName = author ? `${author.firstName} ${author.lastName}` : 'Unknown'
    const note = await RepairNoteService.create(app.db, ticketId, request.user.id, authorName, ticket.status, parsed.data)
    return reply.status(201).send(note)
  })

  app.get('/repair-tickets/:ticketId/notes', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
    const { ticketId } = request.params as { ticketId: string }
    const params = PaginationSchema.parse(request.query)
    const result = await RepairNoteService.listByTicket(app.db, ticketId, params)
    return reply.send(result)
  })

  app.delete('/repair-notes/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const note = await RepairNoteService.delete(app.db, id)
    if (!note) return reply.status(404).send({ error: { message: 'Note not found', statusCode: 404 } })
    return reply.send(note)
  })

  // --- Repair Service Templates ---

  app.post('/repair-service-templates', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
    const parsed = RepairServiceTemplateCreateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const template = await RepairServiceTemplateService.create(app.db, parsed.data)
    return reply.status(201).send(template)
  })

  app.get('/repair-service-templates', { preHandler: [app.authenticate, app.requirePermission('repairs.view')] }, async (request, reply) => {
    const params = PaginationSchema.parse(request.query)
    const result = await RepairServiceTemplateService.list(app.db, params)
    return reply.send(result)
  })

  app.patch('/repair-service-templates/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const parsed = RepairServiceTemplateUpdateSchema.safeParse(request.body)
    if (!parsed.success) {
      return reply.status(400).send({ error: { message: 'Validation failed', details: parsed.error.flatten(), statusCode: 400 } })
    }
    const template = await RepairServiceTemplateService.update(app.db, id, parsed.data)
    if (!template) return reply.status(404).send({ error: { message: 'Template not found', statusCode: 404 } })
    return reply.send(template)
  })

  app.delete('/repair-service-templates/:id', { preHandler: [app.authenticate, app.requirePermission('repairs.admin')] }, async (request, reply) => {
    const { id } = request.params as { id: string }
    const template = await RepairServiceTemplateService.delete(app.db, id)
    if (!template) return reply.status(404).send({ error: { message: 'Template not found', statusCode: 404 } })
    return reply.send(template)
  })
}
