import { TipoTransaccion } from '@prisma/client';
import type { Request, Response } from 'express';
import prisma from '../config/db';
import { listFallbackAppointments } from '../services/appointment.store';
import { listFallbackBudgets } from '../services/budget.store';
import { listFallbackTransactions } from '../services/finance.store';
import { listFallbackProducts } from '../services/inventory.store';
import { listFallbackPatients } from '../services/patient.store';
import { listFallbackRecipes } from '../services/recipe.store';

const startOfToday = () => {
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  return today;
};

const buildReportPayload = (input: {
  totalPacientes: number;
  citasHoy: number;
  ingresosMes: number;
  stockCritico: number;
  presupuestosPendientes: number;
  recetasPendientes: number;
  movimientos: Array<{ tipo: TipoTransaccion; monto: number }>;
}) => {
  const ingresos = input.movimientos
    .filter((movement) => movement.tipo === TipoTransaccion.INGRESO)
    .reduce((sum, movement) => sum + movement.monto, 0);
  const egresos = input.movimientos
    .filter((movement) => movement.tipo === TipoTransaccion.EGRESO)
    .reduce((sum, movement) => sum + movement.monto, 0);

  return {
    kpis: {
      totalPacientes: input.totalPacientes,
      citasHoy: input.citasHoy,
      ingresosMes: input.ingresosMes,
      stockCritico: input.stockCritico,
    },
    modules: [
      { label: 'Presupuestos pendientes', value: input.presupuestosPendientes },
      { label: 'Recetas por firmar', value: input.recetasPendientes },
      { label: 'Movimientos registrados', value: input.movimientos.length },
    ],
    financialBreakdown: [
      { label: 'Ingresos', value: ingresos },
      { label: 'Egresos', value: egresos },
      { label: 'Balance', value: ingresos - egresos },
    ],
  };
};

export const getReportsSummary = async (_req: Request, res: Response) => {
  try {
    const today = startOfToday();
    const monthStart = new Date(today.getFullYear(), today.getMonth(), 1);

    const [patientsCount, appointmentsTodayCount, criticalStockCount, pendingBudgetsCount, pendingRecipesCount, incomeTransactions, allTransactions] =
      await Promise.all([
        prisma.paciente.count(),
        prisma.cita.count({
          where: {
            fecha: {
              gte: today,
            },
          },
        }),
        prisma.producto.count({
          where: {
            stockActual: {
              lte: 5,
            },
          },
        }),
        prisma.presupuesto.count({
          where: {
            estado: 'PENDIENTE',
          },
        }),
        prisma.receta.count({
          where: {
            firmada: false,
          },
        }),
        prisma.transaccion.findMany({
          where: {
            tipo: 'INGRESO',
            fecha: {
              gte: monthStart,
            },
          },
          select: {
            monto: true,
          },
        }),
        prisma.transaccion.findMany({
          select: {
            tipo: true,
            monto: true,
          },
        }),
      ]);

    const ingresosMes = incomeTransactions.reduce((sum, transaction) => sum + transaction.monto, 0);

    res.setHeader('X-Data-Source', 'database');
    return res.json(
      buildReportPayload({
        totalPacientes: patientsCount,
        citasHoy: appointmentsTodayCount,
        ingresosMes,
        stockCritico: criticalStockCount,
        presupuestosPendientes: pendingBudgetsCount,
        recetasPendientes: pendingRecipesCount,
        movimientos: allTransactions,
      }),
    );
  } catch (error) {
    console.warn('Database unavailable for reports, using local fallback store.', error);

    const [patients, appointments, budgets, recipes, inventory, transactions] = await Promise.all([
      listFallbackPatients(),
      listFallbackAppointments(new Date()),
      listFallbackBudgets(),
      listFallbackRecipes(),
      listFallbackProducts(),
      listFallbackTransactions(),
    ]);

    const ingresosMes = transactions
      .filter((transaction) => transaction.tipo === TipoTransaccion.INGRESO)
      .reduce((sum, transaction) => sum + transaction.monto, 0);

    res.setHeader('X-Data-Source', 'local-fallback');
    return res.json(
      buildReportPayload({
        totalPacientes: patients.length,
        citasHoy: appointments.length,
        ingresosMes,
        stockCritico: inventory.filter((item) => item.stockActual <= item.stockMinimo).length,
        presupuestosPendientes: budgets.filter((item) => item.estado === 'PENDIENTE').length,
        recetasPendientes: recipes.filter((item) => !item.firmada).length,
        movimientos: transactions,
      }),
    );
  }
};
