import { Request, Response } from 'express';
import prisma from '../config/db';
import { listFallbackAppointments } from '../services/appointment.store';

type DashboardAgendaItem = {
  id: string;
  time: string;
  period: string;
  patientName: string;
  treatment: string;
  status: string;
  statusColor: 'primary' | 'secondary' | 'amber-400' | 'error';
};

const fallbackAlerts = [
  {
    id: '1',
    type: 'error',
    icon: 'sync_problem',
    title: 'PostgreSQL Desconectado',
    description: 'El backend esta operando en modo fallback local automatizado debido a fallo de conexion.',
    action: 'RECONECTAR',
  },
  {
    id: '2',
    type: 'warning',
    icon: 'inventory_2',
    title: 'Stock Critico: Resina A2',
    description: 'Quedan 2 unidades en inventario. El minimo sugerido es 5.',
    action: 'GENERAR ORDEN',
  },
];

const mapAppointmentStatus = (status: string) => {
  switch (status) {
    case 'CONFIRMADA':
      return { label: 'Confirmada', color: 'secondary' as const };
    case 'EN_SALA':
      return { label: 'En sala', color: 'amber-400' as const };
    case 'ATENDIDA':
      return { label: 'Atendida', color: 'secondary' as const };
    case 'CANCELADA':
      return { label: 'Cancelada', color: 'error' as const };
    case 'NO_ASISTIO':
      return { label: 'No asistio', color: 'error' as const };
    default:
      return { label: 'Programada', color: 'primary' as const };
  }
};

const mapAgendaItem = (input: {
  id: string;
  fecha: Date | string;
  patientName: string;
  treatment: string;
  status: string;
}): DashboardAgendaItem => {
  const dateValue = new Date(input.fecha);
  const hours = dateValue.getHours();
  const statusMeta = mapAppointmentStatus(input.status);

  return {
    id: input.id,
    time: `${hours % 12 || 12}:${dateValue.getMinutes().toString().padStart(2, '0')}`,
    period: hours >= 12 ? 'pm' : 'am',
    patientName: input.patientName,
    treatment: input.treatment || 'Tratamiento',
    status: statusMeta.label,
    statusColor: statusMeta.color,
  };
};

const buildFallbackDashboardData = async () => {
  const appointments = await listFallbackAppointments(new Date());
  const agenda = appointments.map((appointment) =>
    mapAgendaItem({
      id: appointment.id,
      fecha: appointment.fecha,
      patientName: `${appointment.pacienteNombres} ${appointment.pacienteApellidos}`.trim(),
      treatment: appointment.motivo,
      status: appointment.estado,
    }),
  );

  return {
    kpis: {
      citasHoy: { value: agenda.length.toString(), trend: 'Agenda local' },
      ingresosDia: { value: 'S/ 0.00', trend: 'Sincronizacion pendiente' },
      presupuestosHoy: { value: '0', trend: 'Sincronizacion pendiente' },
      deudasPendientes: { value: 'S/ 0.00', trend: 'Sin datos contables' },
    },
    alerts: fallbackAlerts,
    agenda,
  };
};

export const getDashboardSummary = async (req: Request, res: Response) => {
  try {
    const hoyInicio = new Date();
    hoyInicio.setHours(0, 0, 0, 0);
    const hoyFin = new Date();
    hoyFin.setHours(23, 59, 59, 999);

    const citasCount = await prisma.cita.count({
      where: {
        fecha: {
          gte: hoyInicio,
          lte: hoyFin,
        },
      },
    });

    const transacciones = await prisma.transaccion.findMany({
      where: {
        fecha: {
          gte: hoyInicio,
          lte: hoyFin,
        },
        tipo: 'INGRESO',
      },
    });
    const ingresos = transacciones.reduce((sum, transaction) => sum + transaction.monto, 0);

    const presupuestosCount = await prisma.presupuesto.count({
      where: {
        fecha: {
          gte: hoyInicio,
          lte: hoyFin,
        },
      },
    });

    const approvedBudgets = await prisma.presupuesto.findMany({
      where: { estado: 'APROBADO' },
    });
    const totalAprobados = approvedBudgets.reduce((sum, budget) => sum + budget.total, 0);

    const allIngresos = await prisma.transaccion.findMany({
      where: { tipo: 'INGRESO' },
    });
    const totalIngresado = allIngresos.reduce((sum, transaction) => sum + transaction.monto, 0);
    const deudaCalculada = Math.max(0, totalAprobados - totalIngresado);

    const alertasDb = await prisma.alerta.findMany({
      where: { activa: true },
      orderBy: { createdAt: 'desc' },
      take: 4,
    });

    const mappedAlertas = alertasDb.map((alerta) => ({
      id: alerta.id,
      type: alerta.tipo.toLowerCase(),
      icon: alerta.tipo === 'ERROR' ? 'error' : alerta.tipo === 'WARNING' ? 'warning' : 'info',
      title: alerta.titulo,
      description: alerta.descripcion,
      action: alerta.accion || 'VER',
    }));

    const agendaDb = await prisma.cita.findMany({
      where: {
        fecha: {
          gte: hoyInicio,
          lte: hoyFin,
        },
      },
      include: {
        paciente: true,
      },
      orderBy: { fecha: 'asc' },
    });

    const mappedAgenda = agendaDb.map((appointment) =>
      mapAgendaItem({
        id: appointment.id,
        fecha: appointment.fecha,
        patientName: `${appointment.paciente.nombres} ${appointment.paciente.apellidos}`.trim(),
        treatment: appointment.motivo,
        status: appointment.estado,
      }),
    );

    const dashboardData = {
      kpis: {
        citasHoy: { value: citasCount.toString(), trend: 'Hoy' },
        ingresosDia: { value: `S/ ${ingresos.toFixed(2)}`, trend: 'Hoy' },
        presupuestosHoy: { value: presupuestosCount.toString(), trend: 'Hoy' },
        deudasPendientes: { value: `S/ ${deudaCalculada.toFixed(2)}`, trend: 'Global' },
      },
      alerts: mappedAlertas,
      agenda: mappedAgenda,
    };

    res.setHeader('X-Data-Source', 'database');
    return res.json(dashboardData);
  } catch (error) {
    console.warn('Database unavailable for dashboard, using local fallback store.', error);

    try {
      const fallbackDashboardData = await buildFallbackDashboardData();
      res.setHeader('X-Data-Source', 'local-fallback');
      return res.json(fallbackDashboardData);
    } catch (fallbackError) {
      console.error('Error building fallback dashboard:', fallbackError);
    return res.status(500).json({ error: 'Error interno del servidor' });
    }
  }
};
