"use server"

import { ConvexHttpClient } from "convex/browser"

import { api } from "@/convex/_generated/api"
import type { Id } from "@/convex/_generated/dataModel"
import { buildXlsxWorkbook, type WorksheetConfig } from "@/lib/xlsx"
import { REPORT_EXPORT_DEFINITIONS, type ReportExportKey } from "@/lib/report-definitions"
import { requireConvexUrl } from "@/server/convex-client"
import type { DeviceInventoryColumnConfig } from "@/lib/device-inventory-columns"
import { buildInventoryWorksheet, type MachineInventoryRecord } from "@/server/machines/inventory-export"
export type { ReportExportKey }

type ViewerIdentity = {
  tenantId: string
  name: string
  email: string
  avatarUrl?: string | null
  role: string
}

export type ConvexReportContext = {
  client: ConvexHttpClient
  tenantId: string
  viewerId: Id<"users">
}

export async function createConvexContext(identity: ViewerIdentity): Promise<ConvexReportContext> {
  const client = new ConvexHttpClient(requireConvexUrl())
  const ensuredUser = await client.mutation(api.users.ensureUser, {
    tenantId: identity.tenantId,
    name: identity.name,
    email: identity.email,
    avatarUrl: identity.avatarUrl ?? undefined,
    role: identity.role,
  })
  if (!ensuredUser?._id) {
    throw new Error("Não foi possível sincronizar usuário com o Convex")
  }
  return {
    client,
    tenantId: identity.tenantId,
    viewerId: ensuredUser._id as Id<"users">,
  }
}

export type ReportArtifact = {
  fileName: string
  mimeType: string
  buffer: ArrayBuffer
}

type BaseOptions = {
  range?: string
  companyId?: string | null
  dateFrom?: string | null
  dateTo?: string | null
}

export async function buildHoursWorkbook(
  ctx: ConvexReportContext,
  options: BaseOptions & { search?: string }
): Promise<ReportArtifact> {
  const report = await ctx.client.query(api.reports.hoursByClient, {
    tenantId: ctx.tenantId,
    viewerId: ctx.viewerId,
    range: options.range,
    dateFrom: options.dateFrom ?? undefined,
    dateTo: options.dateTo ?? undefined,
  })

  type Item = {
    companyId: string
    name: string
    isAvulso: boolean
    internalMs: number
    externalMs: number
    totalMs: number
    contractedHoursPerMonth: number | null
  }

  let items = (report.items as Item[]) ?? []
  if (options.companyId) {
    items = items.filter((item) => String(item.companyId) === options.companyId)
  }
  if (options.search) {
    const term = options.search.toLowerCase()
    items = items.filter((item) => item.name.toLowerCase().includes(term))
  }

  const summaryRows: Array<Array<unknown>> = [
    ["Relatório", "Horas por cliente"],
    ["Período", report.rangeDays ? `Últimos ${report.rangeDays} dias` : options.range ?? "90d"],
  ]
  if (options.search) summaryRows.push(["Filtro", options.search])
  if (options.companyId) summaryRows.push(["EmpresaId", options.companyId])
  summaryRows.push(["Total de clientes", items.length])

  const dataRows = items.map((item) => {
    const internalHours = item.internalMs / 3_600_000
    const externalHours = item.externalMs / 3_600_000
    const totalHours = item.totalMs / 3_600_000
    const contracted = item.contractedHoursPerMonth
    const usagePct = contracted ? (totalHours / contracted) * 100 : null
    return [
      item.name,
      item.isAvulso ? "Sim" : "Não",
      Number(internalHours.toFixed(2)),
      Number(externalHours.toFixed(2)),
      Number(totalHours.toFixed(2)),
      contracted ?? null,
      usagePct !== null ? Number(usagePct.toFixed(1)) : null,
    ]
  })

  const workbook = buildXlsxWorkbook([
    { name: "Resumo", headers: ["Item", "Valor"], rows: summaryRows },
    {
      name: "Clientes",
      headers: ["Cliente", "Avulso", "Horas internas", "Horas externas", "Horas totais", "Horas contratadas/mês", "% uso"],
      rows: dataRows.length > 0 ? dataRows : [["—", "—", 0, 0, 0, null, null]],
    },
  ])

  const fileName = `hours-by-client-${ctx.tenantId}-${report.rangeDays ?? "90"}d${
    options.companyId ? `-${options.companyId}` : ""
  }${options.search ? `-${encodeURIComponent(options.search)}` : ""}.xlsx`

const arrayBuffer = workbook.buffer.slice(workbook.byteOffset, workbook.byteOffset + workbook.byteLength) as ArrayBuffer
  return {
    fileName,
    mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    buffer: arrayBuffer,
  }
}

export async function buildCategoryInsightsWorkbook(
  ctx: ConvexReportContext,
  options: BaseOptions
): Promise<ReportArtifact> {
  const report = await ctx.client.query(api.reports.categoryInsights, {
    tenantId: ctx.tenantId,
    viewerId: ctx.viewerId,
    range: options.range,
    companyId: (options.companyId ?? undefined) as Id<"companies"> | undefined,
    dateFrom: options.dateFrom ?? undefined,
    dateTo: options.dateTo ?? undefined,
  })

  const categories = (report.categories ?? []) as Array<{
    name: string
    total: number
    resolved: number
    topAgent: { name: string | null; total: number } | null
  }>

  const totalTickets = typeof report.totalTickets === "number"
    ? report.totalTickets
    : categories.reduce((acc, item) => acc + (item.total ?? 0), 0)

  const summaryRows: Array<Array<unknown>> = [
    ["Relatório", "Categorias"],
    ["Período", report.rangeDays ? `Últimos ${report.rangeDays} dias` : options.range ?? "90d"],
    ["Total de tickets", totalTickets],
  ]
  if (options.companyId) summaryRows.push(["EmpresaId", options.companyId])
  if (report.spotlight) {
    summaryRows.push(["Destaque", report.spotlight.categoryName])
    summaryRows.push(["Tickets no destaque", report.spotlight.tickets ?? 0])
    if (report.spotlight.agentName) {
      summaryRows.push(["Agente destaque", report.spotlight.agentName])
    }
  }

  const categoryRows = categories.map((category) => {
    const resolvedRate = category.total > 0 ? (category.resolved / category.total) * 100 : null
    return [
      category.name,
      category.total,
      category.resolved,
      resolvedRate === null ? null : Number(resolvedRate.toFixed(1)),
      category.topAgent?.name ?? "Sem responsável",
      category.topAgent?.total ?? 0,
    ]
  })

  const workbook = buildXlsxWorkbook([
    { name: "Resumo", headers: ["Item", "Valor"], rows: summaryRows },
    {
      name: "Categorias",
      headers: ["Categoria", "Tickets", "Resolvidos", "% resolvidos", "Agente destaque", "Tickets agente"],
      rows: categoryRows.length > 0 ? categoryRows : [["—", 0, 0, null, "—", 0]],
    },
  ])

  const fileName = `category-insights-${ctx.tenantId}-${report.rangeDays ?? "90"}d${
    options.companyId ? `-${options.companyId}` : ""
  }.xlsx`

  const arrayBuffer = workbook.buffer.slice(workbook.byteOffset, workbook.byteOffset + workbook.byteLength) as ArrayBuffer
  return {
    fileName,
    mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    buffer: arrayBuffer,
  }
}

export async function buildMachineCategoryWorkbook(
  ctx: ConvexReportContext,
  options: BaseOptions & { machineId?: string | null; userId?: string | null; columns?: DeviceInventoryColumnConfig[] }
): Promise<ReportArtifact> {
  const response = await ctx.client.query(api.reports.ticketsByMachineAndCategory, {
    tenantId: ctx.tenantId,
    viewerId: ctx.viewerId,
    range: options.range,
    companyId: (options.companyId ?? undefined) as Id<"companies"> | undefined,
    machineId: options.machineId ? (options.machineId as Id<"machines">) : undefined,
    userId: options.userId ? (options.userId as Id<"users">) : undefined,
    dateFrom: options.dateFrom ?? undefined,
    dateTo: options.dateTo ?? undefined,
  }) as {
    rangeDays: number
    items: Array<{
      date: string
      machineHostname: string | null
      machineId: string | null
      companyName: string | null
      categoryName: string
      total: number
    }>
  }

  const items = response.items ?? []
  const summaryRows: Array<Array<unknown>> = [
    ["Relatório", "Máquinas x categorias"],
    [
      "Período",
      response.rangeDays && response.rangeDays > 0
        ? `Últimos ${response.rangeDays} dias`
        : options.range ?? "30d",
    ],
    ["Total de registros", items.length],
  ]
  if (options.companyId) summaryRows.push(["EmpresaId", options.companyId])
  if (options.machineId) summaryRows.push(["MáquinaId", options.machineId])
  if (options.userId) summaryRows.push(["SolicitanteId", options.userId])

  const machineAggregation = new Map<
    string,
    { machine: string; company: string; total: number; categories: Set<string> }
  >()
  for (const item of items) {
    const key = item.machineId ?? item.machineHostname ?? "sem-maquina"
    if (!machineAggregation.has(key)) {
      machineAggregation.set(key, {
        machine: item.machineHostname ?? key,
        company: item.companyName ?? "—",
        total: 0,
        categories: new Set<string>(),
      })
    }
    const entry = machineAggregation.get(key)!
    entry.total += item.total
    entry.categories.add(item.categoryName)
  }

  const perMachineRows = Array.from(machineAggregation.values())
    .sort((a, b) => b.total - a.total)
    .map((entry) => [entry.machine, entry.company, entry.total, Array.from(entry.categories).join(", ")])

  const occurrencesRows = items.map((item) => [
    item.date,
    item.machineHostname ?? "Sem identificação",
    item.companyName ?? "—",
    item.categoryName,
    item.total,
  ])

  const sheets: WorksheetConfig[] = [
    { name: "Resumo", headers: ["Item", "Valor"], rows: summaryRows },
    {
      name: "Máquinas",
      headers: ["Máquina", "Empresa", "Tickets", "Categorias"],
      rows: perMachineRows.length > 0 ? perMachineRows : [["—", "—", 0, "—"]],
    },
    {
      name: "Ocorrências",
      headers: ["Data", "Máquina", "Empresa", "Categoria", "Total"],
      rows: occurrencesRows.length > 0 ? occurrencesRows : [["—", "—", "—", "—", 0]],
    },
  ]

  if (options.columns && options.columns.length > 0) {
    const machineIds = new Set<string>()
    for (const item of items) {
      if (item.machineId) {
        machineIds.add(String(item.machineId))
      }
    }
    if (machineIds.size > 0) {
      const machines = (await ctx.client.query(api.devices.listByTenant, {
        tenantId: ctx.tenantId,
        includeMetadata: true,
      })) as MachineInventoryRecord[]
      const filteredMachines = machines.filter((machine) => machineIds.has(String(machine.id)))
      if (filteredMachines.length > 0) {
        const inventorySheet = buildInventoryWorksheet(filteredMachines, options.columns, "Máquinas detalhadas")
        sheets.push(inventorySheet)
      }
    }
  }

  const workbook = buildXlsxWorkbook(sheets)

  const fileName = `machine-category-${ctx.tenantId}-${options.range ?? response.rangeDays ?? "30"}d${
    options.companyId ? `-${options.companyId}` : ""
  }.xlsx`

  const arrayBuffer = workbook.buffer.slice(workbook.byteOffset, workbook.byteOffset + workbook.byteLength) as ArrayBuffer
  return {
    fileName,
    mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    buffer: arrayBuffer,
  }
}

export async function buildBacklogWorkbook(
  ctx: ConvexReportContext,
  options: BaseOptions
): Promise<ReportArtifact> {
  const report = await ctx.client.query(api.reports.backlogOverview, {
    tenantId: ctx.tenantId,
    viewerId: ctx.viewerId,
    range: options.range,
    companyId: (options.companyId ?? undefined) as Id<"companies"> | undefined,
    dateFrom: options.dateFrom ?? undefined,
    dateTo: options.dateTo ?? undefined,
  })

  const summaryRows: Array<Array<unknown>> = [
    ["Relatório", "Backlog"],
    ["Período", report.rangeDays ? `Últimos ${report.rangeDays} dias` : options.range ?? "90d"],
  ]
  if (options.companyId) summaryRows.push(["EmpresaId", options.companyId])
  summaryRows.push(["Chamados em aberto", report.totalOpen])

  const STATUS_PT: Record<string, string> = {
    PENDING: "Pendentes",
    AWAITING_ATTENDANCE: "Em andamento",
    PAUSED: "Pausados",
    RESOLVED: "Resolvidos",
  }
  const PRIORITY_PT: Record<string, string> = {
    LOW: "Baixa",
    MEDIUM: "Média",
    HIGH: "Alta",
    URGENT: "Crítica",
  }

  const distributionRows: Array<Array<unknown>> = []
  for (const [status, total] of Object.entries(report.statusCounts ?? {})) {
    distributionRows.push(["Status", STATUS_PT[status] ?? status, total])
  }
  for (const [priority, total] of Object.entries(report.priorityCounts ?? {})) {
    distributionRows.push(["Prioridade", PRIORITY_PT[priority] ?? priority, total])
  }
  for (const queue of report.queueCounts ?? []) {
    distributionRows.push(["Fila", queue.name || queue.id, queue.total])
  }

  const workbook = buildXlsxWorkbook([
    { name: "Resumo", headers: ["Item", "Valor"], rows: summaryRows },
    {
      name: "Distribuições",
      headers: ["Categoria", "Chave", "Total"],
      rows: distributionRows.length > 0 ? distributionRows : [["—", "—", 0]],
    },
  ])

  const fileName = `backlog-${ctx.tenantId}-${report.rangeDays ?? "90"}d${
    options.companyId ? `-${options.companyId}` : ""
  }.xlsx`

  const arrayBuffer = workbook.buffer.slice(workbook.byteOffset, workbook.byteOffset + workbook.byteLength) as ArrayBuffer
  return {
    fileName,
    mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    buffer: arrayBuffer,
  }
}

export async function buildSlaWorkbook(
  ctx: ConvexReportContext,
  options: BaseOptions
): Promise<ReportArtifact> {
  const report = await ctx.client.query(api.reports.slaOverview, {
    tenantId: ctx.tenantId,
    viewerId: ctx.viewerId,
    range: options.range,
    companyId: (options.companyId ?? undefined) as Id<"companies"> | undefined,
    dateFrom: options.dateFrom ?? undefined,
    dateTo: options.dateTo ?? undefined,
  })

  const summaryRows: Array<Array<unknown>> = [
    ["Relatório", "Produtividade"],
    ["Período", report.rangeDays ? `Últimos ${report.rangeDays} dias` : options.range ?? "90d"],
  ]
  if (options.companyId) summaryRows.push(["EmpresaId", options.companyId])
  summaryRows.push(["Tickets totais", report.totals.total])
  summaryRows.push(["Tickets abertos", report.totals.open])
  summaryRows.push(["Tickets resolvidos", report.totals.resolved])
  summaryRows.push(["Atrasados (SLA)", report.totals.overdue])
  summaryRows.push(["Tempo médio 1ª resposta (min)", report.response.averageFirstResponseMinutes ?? "—"])
  summaryRows.push(["Respostas registradas", report.response.responsesRegistered ?? 0])
  summaryRows.push(["Tempo médio resolução (min)", report.resolution.averageResolutionMinutes ?? "—"])
  summaryRows.push(["Tickets resolvidos (amostra)", report.resolution.resolvedCount ?? 0])

  const queueRows = (report.queueBreakdown ?? []).map((queue) => [queue.name || queue.id, queue.open])

  const workbook = buildXlsxWorkbook([
    { name: "Resumo", headers: ["Indicador", "Valor"], rows: summaryRows },
    {
      name: "Filas",
      headers: ["Fila", "Chamados abertos"],
      rows: queueRows.length > 0 ? queueRows : [["—", 0]],
    },
  ])

  const fileName = `sla-${ctx.tenantId}-${report.rangeDays ?? "90"}d${
    options.companyId ? `-${options.companyId}` : ""
  }.xlsx`

  const arrayBuffer = workbook.buffer.slice(workbook.byteOffset, workbook.byteOffset + workbook.byteLength) as ArrayBuffer
  return {
    fileName,
    mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    buffer: arrayBuffer,
  }
}

export async function buildCsatWorkbook(
  ctx: ConvexReportContext,
  options: BaseOptions
): Promise<ReportArtifact> {
  const report = await ctx.client.query(api.reports.csatOverview, {
    tenantId: ctx.tenantId,
    viewerId: ctx.viewerId,
    range: options.range,
    companyId: (options.companyId ?? undefined) as Id<"companies"> | undefined,
    dateFrom: options.dateFrom ?? undefined,
    dateTo: options.dateTo ?? undefined,
  })

  const summaryRows: Array<Array<unknown>> = [
    ["Relatório", "CSAT"],
    ["Período", report.rangeDays ? `Últimos ${report.rangeDays} dias` : options.range ?? "90d"],
  ]
  if (options.companyId) summaryRows.push(["EmpresaId", options.companyId])
  summaryRows.push(["CSAT médio", report.averageScore ?? "—"])
  summaryRows.push(["Total de respostas", report.totalSurveys ?? 0])

  const distributionRows = (report.distribution ?? []).map((entry) => [entry.score, entry.total])
  const recentRows = (report.recent ?? []).map((item) => [
    `#${item.reference}`,
    item.score,
    new Date(item.receivedAt).toISOString(),
  ])

  const workbook = buildXlsxWorkbook([
    { name: "Resumo", headers: ["Métrica", "Valor"], rows: summaryRows },
    {
      name: "Distribuição",
      headers: ["Nota", "Total"],
      rows: distributionRows.length > 0 ? distributionRows : [["—", 0]],
    },
    {
      name: "Respostas recentes",
      headers: ["Ticket", "Nota", "Recebido em"],
      rows: recentRows.length > 0 ? recentRows : [["—", "—", "—"]],
    },
  ])

  const fileName = `csat-${ctx.tenantId}-${report.rangeDays ?? "90"}d${
    options.companyId ? `-${options.companyId}` : ""
  }.xlsx`

  const arrayBuffer = workbook.buffer.slice(workbook.byteOffset, workbook.byteOffset + workbook.byteLength) as ArrayBuffer
  return {
    fileName,
    mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    buffer: arrayBuffer,
  }
}

export async function buildTicketsByChannelWorkbook(
  ctx: ConvexReportContext,
  options: BaseOptions
): Promise<ReportArtifact> {
  const report = await ctx.client.query(api.reports.ticketsByChannel, {
    tenantId: ctx.tenantId,
    viewerId: ctx.viewerId,
    range: options.range,
    companyId: (options.companyId ?? undefined) as Id<"companies"> | undefined,
  })

  const CHANNEL_PT: Record<string, string> = {
    EMAIL: "E-mail",
    PHONE: "Telefone",
    CHAT: "Chat",
    WHATSAPP: "WhatsApp",
    API: "API",
    MANUAL: "Manual",
    WEB: "Portal",
    PORTAL: "Portal",
  }

  const summaryRows: Array<Array<unknown>> = [
    ["Relatório", "Tickets por canal"],
    ["Período", report.rangeDays ? `Últimos ${report.rangeDays} dias` : options.range ?? "90d"],
  ]
  if (options.companyId) summaryRows.push(["EmpresaId", options.companyId])
  summaryRows.push(["Total de linhas", report.points.length])

  const header = ["Data", ...(report.channels ?? []).map((ch) => CHANNEL_PT[ch] ?? ch)]
  const dataRows = (report.points ?? []).map((point) => [
    point.date,
    ...(report.channels ?? []).map((ch) => point.values[ch] ?? 0),
  ])

  const workbook = buildXlsxWorkbook([
    { name: "Resumo", headers: ["Item", "Valor"], rows: summaryRows },
    {
      name: "Distribuição",
      headers: header,
      rows: dataRows.length > 0 ? dataRows : [[new Date().toISOString().slice(0, 10), ...(report.channels ?? []).map(() => 0)]],
    },
  ])

  const fileName = `tickets-by-channel-${ctx.tenantId}-${options.range ?? "90d"}${
    options.companyId ? `-${options.companyId}` : ""
  }.xlsx`

  const arrayBuffer = workbook.buffer.slice(workbook.byteOffset, workbook.byteOffset + workbook.byteLength) as ArrayBuffer
  return {
    fileName,
    mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    buffer: arrayBuffer,
  }
}
