import { Injectable } from "@nestjs/common";
import { CashMovementType, EquipmentStatus } from "@prisma/client";
import { PrismaService } from "../../infra/prisma/prisma.service";

@Injectable()
export class DashboardService {
  constructor(private readonly prisma: PrismaService) {}

  async summary(companyId: string) {
    const now = new Date();
    const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
    const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
    const startOfYear = new Date(now.getFullYear(), 0, 1);

    const [
      activeCustomers,
      delinquentCustomers,
      activeRentals,
      availableEquipment,
      rentedEquipment,
      maintenanceEquipment,
      reservedEquipment,
      totalEquipment,
      receivablesMonth,
      receivablesYear,
      rentalsCountYear,
      payablesMonth,
      cashMovementsMonth,
    ] = await Promise.all([
      this.prisma.customer.count({ where: { companyId, status: "ACTIVE" } }),
      this.prisma.customer.count({ where: { companyId, status: "DELINQUENT" } }),
      this.prisma.rental.count({ where: { companyId, status: "IN_PROGRESS" } }),
      this.prisma.equipment.count({ where: { companyId, status: EquipmentStatus.AVAILABLE } }),
      this.prisma.equipment.count({ where: { companyId, status: EquipmentStatus.RENTED } }),
      this.prisma.equipment.count({ where: { companyId, status: EquipmentStatus.MAINTENANCE } }),
      this.prisma.equipment.count({ where: { companyId, status: EquipmentStatus.RESERVED } }),
      this.prisma.equipment.count({ where: { companyId } }),
      this.prisma.accountReceivable.aggregate({
        where: {
          companyId,
          dueDate: { gte: startOfMonth, lte: endOfMonth },
        },
        _sum: { amount: true },
      }),
      this.prisma.accountReceivable.aggregate({
        where: {
          companyId,
          dueDate: { gte: startOfYear },
        },
        _sum: { amount: true },
      }),
      this.prisma.rental.count({ where: { companyId, createdAt: { gte: startOfYear } } }),
      this.prisma.accountPayable.aggregate({
        where: {
          companyId,
          dueDate: { gte: startOfMonth, lte: endOfMonth },
        },
        _sum: { amount: true },
      }),
      this.prisma.cashMovement.findMany({
        where: {
          companyId,
          occurredAt: { gte: startOfMonth, lte: endOfMonth },
        },
      }),
    ]);

    let revenueMonth = Number(receivablesMonth._sum.amount ?? 0);
    let revenueYear = Number(receivablesYear._sum.amount ?? 0);

    if (revenueMonth === 0) {
      const rentalMonthSum = await this.prisma.rental.aggregate({
        where: {
          companyId,
          startDate: { gte: startOfMonth, lte: endOfMonth },
        },
        _sum: { total: true },
      });
      revenueMonth = Number(rentalMonthSum._sum.total ?? 0);
    }

    if (revenueYear === 0) {
      const rentalYearSum = await this.prisma.rental.aggregate({
        where: {
          companyId,
          startDate: { gte: startOfYear },
        },
        _sum: { total: true },
      });
      revenueYear = Number(rentalYearSum._sum.total ?? 0);
    }

    const totalPayablesMonth = Number(payablesMonth._sum.amount ?? 0);
    let cashFlow = revenueMonth - totalPayablesMonth;

    if (cashMovementsMonth.length > 0) {
      cashFlow = cashMovementsMonth.reduce((acc, m) => {
        const amt = Number(m.amount);
        return m.type === CashMovementType.INCOME ? acc + amt : acc - amt;
      }, 0);
    }

    const occupancyRate = totalEquipment > 0 ? Math.round((rentedEquipment / totalEquipment) * 100) : 0;
    const averageTicket =
      activeRentals > 0
        ? Math.round(revenueMonth / activeRentals)
        : rentalsCountYear > 0
          ? Math.round(revenueYear / rentalsCountYear)
          : 0;

    const monthNames = ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"];
    const revenueChart = [];
    for (let i = 6; i >= 0; i--) {
      const d = new Date(now.getFullYear(), now.getMonth() - i, 1);
      const mEnd = new Date(d.getFullYear(), d.getMonth() + 1, 0, 23, 59, 59);
      const rec = await this.prisma.accountReceivable.aggregate({
        where: {
          companyId,
          dueDate: { gte: d, lte: mEnd },
        },
        _sum: { amount: true },
      });
      let val = Number(rec._sum.amount ?? 0);
      if (val === 0) {
        const ren = await this.prisma.rental.aggregate({
          where: {
            companyId,
            startDate: { gte: d, lte: mEnd },
          },
          _sum: { total: true },
        });
        val = Number(ren._sum.total ?? 0);
      }
      revenueChart.push({
        month: monthNames[d.getMonth()],
        value: val,
      });
    }

    const statusChart = [
      { name: "Disponível", value: availableEquipment, color: "#16a34a" },
      { name: "Locado", value: rentedEquipment, color: "#2563eb" },
      { name: "Manutenção", value: maintenanceEquipment, color: "#dc2626" },
      { name: "Reservado", value: reservedEquipment, color: "#f59e0b" },
    ];

    return {
      revenueMonth,
      revenueYear,
      activeRentals,
      availableEquipment,
      rentedEquipment,
      maintenanceEquipment,
      reservedEquipment,
      totalEquipment,
      activeCustomers,
      delinquentCustomers,
      occupancyRate,
      averageTicket,
      cashFlow,
      revenueChart,
      statusChart,
    };
  }
}
