'use server';

import { and, eq } from 'drizzle-orm';
import { revalidatePath } from 'next/cache';
import { db } from '@/db';
import { leads, leadEstadoHistory, leadPipelineEventos, precisionHistory } from '@/db/schema';
import { getCurrentTenantId as getTenantId } from '@/lib/auth/current-user';
import { getPricingConfig, getCatalog } from '@/db/pricing-queries';
import { computeBudget } from '@/budget';
import type { BudgetInputs } from '@/budget/types';

type Estado = (typeof leads.estado.enumValues)[number];

export async function cambiarEstado(leadId: string, estado: Estado) {
  const tenantId = await getTenantId();

  const [updated] = await db
    .update(leads)
    .set({ estado, updatedAt: new Date() })
    .where(and(eq(leads.id, leadId), eq(leads.tenantId, tenantId)))
    .returning();

  if (!updated) throw new Error('Lead no encontrado.');

  await db.insert(leadEstadoHistory).values({ leadId, estado });

  revalidatePath('/panel');
  revalidatePath(`/panel/${leadId}`);
}

export async function marcarGanado(leadId: string, precioFinalEuros: number) {
  const tenantId = await getTenantId();

  const [lead] = await db
    .select()
    .from(leads)
    .where(and(eq(leads.id, leadId), eq(leads.tenantId, tenantId)))
    .limit(1);

  if (!lead) throw new Error('Lead no encontrado.');
  if (lead.presupuestoEstimado == null) {
    throw new Error('El lead no tiene presupuesto estimado, no se puede calcular la precisión.');
  }

  const finalCents = Math.round(precioFinalEuros * 100);
  const deltaPct = ((finalCents - lead.presupuestoEstimado) / lead.presupuestoEstimado) * 100;

  await db.update(leads).set({ estado: 'ganado', updatedAt: new Date() }).where(eq(leads.id, leadId));
  await db.insert(leadEstadoHistory).values({ leadId, estado: 'ganado' });
  await db.insert(precisionHistory).values({
    leadId,
    estimated: lead.presupuestoEstimado,
    final: finalCents,
    deltaPct: deltaPct.toFixed(2),
  });

  revalidatePath('/panel');
  revalidatePath(`/panel/${leadId}`);
}

export async function recalcularPresupuesto(leadId: string) {
  const tenantId = await getTenantId();
  const [lead] = await db
    .select()
    .from(leads)
    .where(and(eq(leads.id, leadId), eq(leads.tenantId, tenantId)))
    .limit(1);
  if (!lead) throw new Error('Lead no encontrado.');

  const [config, catalog] = await Promise.all([getPricingConfig(), getCatalog()]);

  const inputs: BudgetInputs = {
    tipoReforma: lead.tipoReforma ?? 'otro',
    m2Suelo: lead.m2Suelo ?? null,
    alturaTecho: lead.alturaTecho ?? null,
    calidadGlobal: lead.calidadGlobal ?? 'media',
    estructural: lead.estructural,
    provincia: lead.provincia ?? null,
    materialSelections: (lead.materialSelections as Record<string, string>) ?? {},
  };

  const result = computeBudget(inputs, config, catalog);

  await db
    .update(leads)
    .set({
      presupuestoEstimado: result.total,
      desgloseSnapshot: { stage: lead.pipelineStage, result },
      updatedAt: new Date(),
    })
    .where(eq(leads.id, leadId));

  await db.insert(leadPipelineEventos).values({
    leadId,
    stage: 'presupuesto_generado',
    metadata: { total: result.total, confianza: result.confianza },
  });

  revalidatePath('/panel');
  revalidatePath(`/panel/${leadId}`);
}
