import jsPDF from 'jspdf';
import autoTable from 'jspdf-autotable';
import { formatUsd, bsDesdeUsd, formatBs, ESTADO_META, ESTADO_PAGO_META, type EstadoPedido, type EstadoPago } from '@gustito/shared';
import { supabase } from './supabase';

interface ItemReporte {
  nombre: string;
  cantidad: number;
  precio_usd: number;
  nota: string | null;
}
interface FilaReporte {
  codigo: string;
  tipo_entrega: string;
  mesa: string | null;
  total_usd: number;
  metodo_pago: string;
  estado: string;
  recibido_en: string;
  pagos: { estado: string }[];
  pedido_items: ItemReporte[];
}

// Carga una imagen (logo) y la devuelve como dataURL PNG + su tamano. Null si falla.
async function cargarLogo(url: string): Promise<{ dataUrl: string; w: number; h: number } | null> {
  try {
    const img = await new Promise<HTMLImageElement>((res, rej) => {
      const i = new Image();
      i.crossOrigin = 'anonymous';
      i.onload = () => res(i);
      i.onerror = rej;
      i.src = url;
    });
    const canvas = document.createElement('canvas');
    canvas.width = img.naturalWidth;
    canvas.height = img.naturalHeight;
    const ctx = canvas.getContext('2d');
    if (!ctx) return null;
    ctx.drawImage(img, 0, 0);
    return { dataUrl: canvas.toDataURL('image/png'), w: img.naturalWidth, h: img.naturalHeight };
  } catch {
    return null;
  }
}

export async function generarReportePDF(restauranteId: string, nombre: string, tasa: number | null, desde?: string | null) {
  // La jornada arranca en el ultimo cierre de caja (no a medianoche); si se
  // pasa "desde", el reporte cubre solo desde ahi.
  let q = supabase
    .from('pedidos')
    .select(
      'codigo, tipo_entrega, mesa, total_usd, metodo_pago, estado, recibido_en, pagos(estado), pedido_items(nombre, cantidad, precio_usd, nota)',
    )
    .eq('restaurante_id', restauranteId);
  if (desde) q = q.gte('recibido_en', desde);
  const [{ data: rest }, { data, error }] = await Promise.all([
    supabase.from('restaurantes').select('logo_url, direccion, telefono').eq('id', restauranteId).maybeSingle(),
    q.order('recibido_en', { ascending: true }),
  ]);
  if (error) throw error;
  const pedidos = (data ?? []) as unknown as FilaReporte[];
  const info = (rest ?? {}) as { logo_url?: string | null; direccion?: string | null; telefono?: string | null };

  const doc = new jsPDF();
  const fecha = new Date().toLocaleString('es-VE');

  // Encabezado: logo + nombre + direccion + telefono
  let headX = 14;
  if (info.logo_url) {
    const logo = await cargarLogo(info.logo_url);
    if (logo) {
      const box = 22;
      const escala = Math.min(box / logo.w, box / logo.h);
      const w = logo.w * escala;
      const h = logo.h * escala;
      doc.addImage(logo.dataUrl, 'PNG', 14, 10, w, h);
      headX = 14 + box + 4;
    }
  }
  doc.setFontSize(16);
  doc.setTextColor(0);
  doc.text(nombre, headX, 17);
  doc.setFontSize(9);
  doc.setTextColor(120);
  let hy = 23;
  if (info.direccion) {
    doc.text(doc.splitTextToSize(info.direccion, 130), headX, hy);
    hy += 5;
  }
  if (info.telefono) {
    doc.text(`Tel: ${info.telefono}`, headX, hy);
    hy += 5;
  }
  doc.text('Reporte de ventas · ' + fecha, headX, hy);

  // Resumen
  const validos = pedidos.filter((p) => p.estado !== 'cancelado');
  const totalUsd = validos.reduce((a, p) => a + Number(p.total_usd), 0);
  const porMetodo: Record<string, number> = {};
  for (const p of validos) porMetodo[p.metodo_pago] = (porMetodo[p.metodo_pago] || 0) + Number(p.total_usd);
  const pagados = validos.filter((p) => p.pagos?.[0]?.estado === 'confirmado').length;

  const y = Math.max(38, hy + 8);
  doc.setTextColor(0);
  doc.setFontSize(11);
  doc.text(`Pedidos: ${validos.length}`, 14, y);
  doc.text(`Ventas: ${formatUsd(totalUsd)}${tasa ? ' · ' + formatBs(bsDesdeUsd(totalUsd, tasa)) : ''}`, 14, y + 6);
  doc.text(`Pagos confirmados: ${pagados} de ${validos.length}`, 14, y + 12);
  doc.setFontSize(9);
  doc.setTextColor(90);
  doc.text(
    Object.entries(porMetodo)
      .map(([m, v]) => `${m}: ${formatUsd(v)}`)
      .join('    '),
    14,
    y + 18,
  );

  // Productos vendidos (que se vendio y cuanto) — agregado por producto + variante
  const agg = new Map<string, { cantidad: number; total: number }>();
  for (const p of validos) {
    for (const it of p.pedido_items ?? []) {
      const clave = it.nombre + (it.nota ? ` · ${it.nota}` : '');
      const a = agg.get(clave) ?? { cantidad: 0, total: 0 };
      a.cantidad += Number(it.cantidad);
      a.total += Number(it.precio_usd) * Number(it.cantidad);
      agg.set(clave, a);
    }
  }
  const productos = [...agg.entries()].sort((a, b) => b[1].total - a[1].total);

  doc.setTextColor(0);
  doc.setFontSize(12);
  doc.text('Productos vendidos', 14, y + 28);
  autoTable(doc, {
    startY: y + 31,
    head: [['Producto', 'Cantidad', 'Total']],
    body:
      productos.length > 0
        ? productos.map(([nom, v]) => [nom, String(v.cantidad), formatUsd(v.total)])
        : [['Sin ventas todavia', '', '']],
    styles: { fontSize: 9 },
    headStyles: { fillColor: [201, 162, 39] },
  });

  // Detalle por pedido
  const yTabla = (doc as unknown as { lastAutoTable?: { finalY: number } }).lastAutoTable?.finalY ?? y + 40;
  doc.setFontSize(12);
  doc.text('Detalle por pedido', 14, yTabla + 10);
  autoTable(doc, {
    startY: yTabla + 13,
    head: [['Codigo', 'Tipo', 'Total', 'Metodo', 'Pago', 'Estado']],
    body: pedidos.map((p) => [
      p.codigo,
      p.tipo_entrega === 'mesa' ? 'Mesa ' + (p.mesa ?? '') : p.tipo_entrega,
      formatUsd(p.total_usd),
      p.metodo_pago,
      ESTADO_PAGO_META[(p.pagos?.[0]?.estado ?? 'pendiente') as EstadoPago]?.label ?? '',
      ESTADO_META[p.estado as EstadoPedido]?.label ?? p.estado,
    ]),
    styles: { fontSize: 9 },
    headStyles: { fillColor: [249, 115, 22] },
  });

  doc.save(`reporte-${nombre.toLowerCase().replace(/[^a-z0-9]+/g, '-')}.pdf`);
}
