import { v } from "convex/values"
import { mutation, query, type QueryCtx, type MutationCtx } from "./_generated/server"
import type { Id } from "./_generated/dataModel"

const EMPRESTIMO_STATUS = ["ATIVO", "DEVOLVIDO", "ATRASADO", "CANCELADO"] as const
type EmprestimoStatus = (typeof EMPRESTIMO_STATUS)[number]

const EQUIPAMENTO_TIPOS = [
  "NOTEBOOK",
  "DESKTOP",
  "MONITOR",
  "TECLADO",
  "MOUSE",
  "HEADSET",
  "WEBCAM",
  "IMPRESSORA",
  "SCANNER",
  "PROJETOR",
  "TABLET",
  "CELULAR",
  "ROTEADOR",
  "SWITCH",
  "OUTRO",
] as const

async function getNextReference(ctx: MutationCtx, tenantId: string): Promise<number> {
  const last = await ctx.db
    .query("emprestimos")
    .withIndex("by_tenant_reference", (q) => q.eq("tenantId", tenantId))
    .order("desc")
    .first()
  return (last?.reference ?? 0) + 1
}

export const list = query({
  args: {
    tenantId: v.string(),
    viewerId: v.id("users"),
    status: v.optional(v.string()),
    clienteId: v.optional(v.id("companies")),
    tecnicoId: v.optional(v.id("users")),
    limit: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const { tenantId, status, clienteId, tecnicoId, limit = 100 } = args

    let baseQuery = ctx.db
      .query("emprestimos")
      .withIndex("by_tenant_created", (q) => q.eq("tenantId", tenantId))
      .order("desc")

    const all = await baseQuery.take(limit * 2)

    let filtered = all
    if (status) {
      filtered = filtered.filter((e) => e.status === status)
    }
    if (clienteId) {
      filtered = filtered.filter((e) => e.clienteId === clienteId)
    }
    if (tecnicoId) {
      filtered = filtered.filter((e) => e.tecnicoId === tecnicoId)
    }

    return filtered.slice(0, limit).map((emprestimo) => ({
      id: emprestimo._id,
      reference: emprestimo.reference,
      clienteId: emprestimo.clienteId,
      clienteNome: emprestimo.clienteSnapshot.name,
      responsavelNome: emprestimo.responsavelNome,
      responsavelContato: emprestimo.responsavelContato,
      tecnicoId: emprestimo.tecnicoId,
      tecnicoNome: emprestimo.tecnicoSnapshot.name,
      tecnicoEmail: emprestimo.tecnicoSnapshot.email,
      equipamentos: emprestimo.equipamentos,
      quantidade: emprestimo.quantidade,
      valor: emprestimo.valor,
      dataEmprestimo: emprestimo.dataEmprestimo,
      dataFimPrevisto: emprestimo.dataFimPrevisto,
      dataDevolucao: emprestimo.dataDevolucao,
      status: emprestimo.status,
      observacoes: emprestimo.observacoes,
      observacoesDevolucao: emprestimo.observacoesDevolucao,
      multaDiaria: emprestimo.multaDiaria,
      multaCalculada: emprestimo.multaCalculada,
      createdAt: emprestimo.createdAt,
      updatedAt: emprestimo.updatedAt,
    }))
  },
})

export const getById = query({
  args: {
    id: v.id("emprestimos"),
    viewerId: v.id("users"),
  },
  handler: async (ctx, args) => {
    const emprestimo = await ctx.db.get(args.id)
    if (!emprestimo) return null

    return {
      id: emprestimo._id,
      reference: emprestimo.reference,
      clienteId: emprestimo.clienteId,
      clienteSnapshot: emprestimo.clienteSnapshot,
      responsavelNome: emprestimo.responsavelNome,
      responsavelContato: emprestimo.responsavelContato,
      tecnicoId: emprestimo.tecnicoId,
      tecnicoSnapshot: emprestimo.tecnicoSnapshot,
      equipamentos: emprestimo.equipamentos,
      quantidade: emprestimo.quantidade,
      valor: emprestimo.valor,
      dataEmprestimo: emprestimo.dataEmprestimo,
      dataFimPrevisto: emprestimo.dataFimPrevisto,
      dataDevolucao: emprestimo.dataDevolucao,
      status: emprestimo.status,
      observacoes: emprestimo.observacoes,
      multaDiaria: emprestimo.multaDiaria,
      multaCalculada: emprestimo.multaCalculada,
      createdBy: emprestimo.createdBy,
      createdAt: emprestimo.createdAt,
      updatedAt: emprestimo.updatedAt,
    }
  },
})

export const create = mutation({
  args: {
    tenantId: v.string(),
    createdBy: v.id("users"),
    clienteId: v.id("companies"),
    responsavelNome: v.string(),
    responsavelContato: v.optional(v.string()),
    tecnicoId: v.id("users"),
    equipamentos: v.array(v.object({
      id: v.string(),
      tipo: v.string(),
      marca: v.string(),
      modelo: v.string(),
      serialNumber: v.optional(v.string()),
      patrimonio: v.optional(v.string()),
    })),
    valor: v.optional(v.number()),
    dataEmprestimo: v.number(),
    dataFimPrevisto: v.number(),
    observacoes: v.optional(v.string()),
    multaDiaria: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const now = Date.now()
    const reference = await getNextReference(ctx, args.tenantId)

    const cliente = await ctx.db.get(args.clienteId)
    if (!cliente) {
      throw new Error("Cliente nao encontrado")
    }

    const tecnico = await ctx.db.get(args.tecnicoId)
    if (!tecnico) {
      throw new Error("Tecnico nao encontrado")
    }

    const emprestimoId = await ctx.db.insert("emprestimos", {
      tenantId: args.tenantId,
      reference,
      clienteId: args.clienteId,
      clienteSnapshot: {
        name: cliente.name,
        slug: cliente.slug,
      },
      responsavelNome: args.responsavelNome,
      responsavelContato: args.responsavelContato,
      tecnicoId: args.tecnicoId,
      tecnicoSnapshot: {
        name: tecnico.name,
        email: tecnico.email,
      },
      equipamentos: args.equipamentos,
      quantidade: args.equipamentos.length,
      valor: args.valor,
      dataEmprestimo: args.dataEmprestimo,
      dataFimPrevisto: args.dataFimPrevisto,
      status: "ATIVO",
      observacoes: args.observacoes,
      multaDiaria: args.multaDiaria,
      createdBy: args.createdBy,
      createdAt: now,
      updatedAt: now,
    })

    const creator = await ctx.db.get(args.createdBy)
    await ctx.db.insert("emprestimoHistorico", {
      tenantId: args.tenantId,
      emprestimoId,
      tipo: "CRIADO",
      descricao: `Emprestimo #${reference} criado`,
      autorId: args.createdBy,
      autorSnapshot: {
        name: creator?.name ?? "Sistema",
        email: creator?.email,
      },
      createdAt: now,
    })

    return { id: emprestimoId, reference }
  },
})

export const devolver = mutation({
  args: {
    id: v.id("emprestimos"),
    updatedBy: v.id("users"),
    observacoes: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const emprestimo = await ctx.db.get(args.id)
    if (!emprestimo) {
      throw new Error("Emprestimo nao encontrado")
    }

    if (emprestimo.status === "DEVOLVIDO") {
      throw new Error("Emprestimo ja foi devolvido")
    }

    const now = Date.now()
    let multaCalculada: number | undefined

    if (emprestimo.multaDiaria && now > emprestimo.dataFimPrevisto) {
      const diasAtraso = Math.ceil((now - emprestimo.dataFimPrevisto) / (1000 * 60 * 60 * 24))
      multaCalculada = diasAtraso * emprestimo.multaDiaria
    }

    await ctx.db.patch(args.id, {
      status: "DEVOLVIDO",
      dataDevolucao: now,
      multaCalculada,
      observacoesDevolucao: args.observacoes,
      updatedBy: args.updatedBy,
      updatedAt: now,
    })

    const updater = await ctx.db.get(args.updatedBy)
    await ctx.db.insert("emprestimoHistorico", {
      tenantId: emprestimo.tenantId,
      emprestimoId: args.id,
      tipo: "DEVOLVIDO",
      descricao: `Emprestimo #${emprestimo.reference} devolvido${multaCalculada ? ` com multa de R$ ${multaCalculada.toFixed(2)}` : ""}`,
      alteracoes: { multaCalculada },
      autorId: args.updatedBy,
      autorSnapshot: {
        name: updater?.name ?? "Sistema",
        email: updater?.email,
      },
      createdAt: now,
    })

    return { ok: true, multaCalculada }
  },
})

export const update = mutation({
  args: {
    id: v.id("emprestimos"),
    updatedBy: v.id("users"),
    responsavelNome: v.optional(v.string()),
    responsavelContato: v.optional(v.string()),
    dataFimPrevisto: v.optional(v.number()),
    observacoes: v.optional(v.string()),
    multaDiaria: v.optional(v.number()),
    status: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const emprestimo = await ctx.db.get(args.id)
    if (!emprestimo) {
      throw new Error("Emprestimo nao encontrado")
    }

    const now = Date.now()
    const updates: Record<string, unknown> = {
      updatedBy: args.updatedBy,
      updatedAt: now,
    }

    if (args.responsavelNome !== undefined) updates.responsavelNome = args.responsavelNome
    if (args.responsavelContato !== undefined) updates.responsavelContato = args.responsavelContato
    if (args.dataFimPrevisto !== undefined) updates.dataFimPrevisto = args.dataFimPrevisto
    if (args.observacoes !== undefined) updates.observacoes = args.observacoes
    if (args.multaDiaria !== undefined) updates.multaDiaria = args.multaDiaria
    if (args.status !== undefined) updates.status = args.status

    await ctx.db.patch(args.id, updates)

    const updater = await ctx.db.get(args.updatedBy)
    await ctx.db.insert("emprestimoHistorico", {
      tenantId: emprestimo.tenantId,
      emprestimoId: args.id,
      tipo: "MODIFICADO",
      descricao: `Emprestimo #${emprestimo.reference} atualizado`,
      alteracoes: updates,
      autorId: args.updatedBy,
      autorSnapshot: {
        name: updater?.name ?? "Sistema",
        email: updater?.email,
      },
      createdAt: now,
    })

    return { ok: true }
  },
})

export const getHistorico = query({
  args: {
    emprestimoId: v.id("emprestimos"),
    limit: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const historico = await ctx.db
      .query("emprestimoHistorico")
      .withIndex("by_emprestimo_created", (q) => q.eq("emprestimoId", args.emprestimoId))
      .order("desc")
      .take(args.limit ?? 50)

    return historico.map((h) => ({
      id: h._id,
      tipo: h.tipo,
      descricao: h.descricao,
      alteracoes: h.alteracoes,
      autorNome: h.autorSnapshot.name,
      createdAt: h.createdAt,
    }))
  },
})

export const getStats = query({
  args: {
    tenantId: v.string(),
    viewerId: v.id("users"),
  },
  handler: async (ctx, args) => {
    const all = await ctx.db
      .query("emprestimos")
      .withIndex("by_tenant", (q) => q.eq("tenantId", args.tenantId))
      .take(200)

    const now = Date.now()
    const ativos = all.filter((e) => e.status === "ATIVO")
    const atrasados = ativos.filter((e) => e.dataFimPrevisto < now)
    const devolvidos = all.filter((e) => e.status === "DEVOLVIDO")

    return {
      total: all.length,
      ativos: ativos.length,
      atrasados: atrasados.length,
      devolvidos: devolvidos.length,
      valorTotalAtivo: ativos.reduce((sum, e) => sum + (e.valor ?? 0), 0),
    }
  },
})
