import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';

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

  private serializeBigInt(data: any): any {
    return JSON.parse(
      JSON.stringify(data, (_, v) => (typeof v === 'bigint' ? Number(v) : v)),
    );
  }

  async getRevenueSummary(userId: number, year: number) {
    const startDate = new Date(year, 0, 1);
    const endDate = new Date(year, 11, 31, 23, 59, 59, 999);

    const settlements = await this.prisma.settlement.findMany({
      where: {
        userId,
        paymentStatus: 'paid',
        settlementDate: {
          gte: startDate,
          lte: endDate,
        },
      },
      select: {
        totalAmount: true,
        settlementDate: true,
      },
    });

    // Group by month
    const monthly: { month: number; revenue: number }[] = [];
    for (let m = 1; m <= 12; m++) {
      const monthSettlements = settlements.filter((s) => {
        const date = new Date(s.settlementDate);
        return date.getMonth() + 1 === m;
      });

      const revenue = monthSettlements.reduce(
        (sum, s) => sum + s.totalAmount,
        BigInt(0),
      );

      monthly.push({ month: m, revenue: Number(revenue) });
    }

    const totalRevenue = settlements.reduce(
      (sum, s) => sum + s.totalAmount,
      BigInt(0),
    );

    return {
      year,
      totalRevenue: Number(totalRevenue),
      monthly,
    };
  }

  async getExpenseSummary(userId: number, year: number) {
    const startDate = new Date(year, 0, 1);
    const endDate = new Date(year, 11, 31, 23, 59, 59, 999);

    const expenses = await this.prisma.expense.findMany({
      where: {
        userId,
        expenseDate: {
          gte: startDate,
          lte: endDate,
        },
      },
      select: {
        amount: true,
        expenseDate: true,
      },
    });

    // Group by month
    const monthly: { month: number; expenses: number }[] = [];
    for (let m = 1; m <= 12; m++) {
      const monthExpenses = expenses.filter((e) => {
        const date = new Date(e.expenseDate);
        return date.getMonth() + 1 === m;
      });

      const total = monthExpenses.reduce(
        (sum, e) => sum + e.amount,
        BigInt(0),
      );

      monthly.push({ month: m, expenses: Number(total) });
    }

    const totalExpenses = expenses.reduce(
      (sum, e) => sum + e.amount,
      BigInt(0),
    );

    return {
      year,
      totalExpenses: Number(totalExpenses),
      monthly,
    };
  }

  async getProfitLoss(userId: number, year: number) {
    const [revenueSummary, expenseSummary] = await Promise.all([
      this.getRevenueSummary(userId, year),
      this.getExpenseSummary(userId, year),
    ]);

    const monthly = revenueSummary.monthly.map((rev, index) => {
      const exp = expenseSummary.monthly[index];
      return {
        month: rev.month,
        revenue: rev.revenue,
        expenses: exp.expenses,
        profit: rev.revenue - exp.expenses,
      };
    });

    return {
      year,
      totalRevenue: revenueSummary.totalRevenue,
      totalExpenses: expenseSummary.totalExpenses,
      totalProfit: revenueSummary.totalRevenue - expenseSummary.totalExpenses,
      monthly,
    };
  }

  async getTaxSummary(userId: number, year: number) {
    const startDate = new Date(year, 0, 1);
    const endDate = new Date(year, 11, 31, 23, 59, 59, 999);

    const records = await this.prisma.purchaseSaleRecord.findMany({
      where: {
        userId,
        recordDate: {
          gte: startDate,
          lte: endDate,
        },
      },
      select: {
        tradeType: true,
        supplyAmount: true,
        taxAmount: true,
        total: true,
      },
    });

    const sales = records.filter((r) => r.tradeType === 'sale');
    const purchases = records.filter((r) => r.tradeType === 'purchase');

    const saleTotals = {
      supplyAmount: Number(
        sales.reduce((sum, r) => sum + r.supplyAmount, BigInt(0)),
      ),
      taxAmount: Number(
        sales.reduce((sum, r) => sum + r.taxAmount, BigInt(0)),
      ),
      total: Number(sales.reduce((sum, r) => sum + r.total, BigInt(0))),
    };

    const purchaseTotals = {
      supplyAmount: Number(
        purchases.reduce((sum, r) => sum + r.supplyAmount, BigInt(0)),
      ),
      taxAmount: Number(
        purchases.reduce((sum, r) => sum + r.taxAmount, BigInt(0)),
      ),
      total: Number(purchases.reduce((sum, r) => sum + r.total, BigInt(0))),
    };

    return {
      year,
      sales: saleTotals,
      purchases: purchaseTotals,
      netTax: saleTotals.taxAmount - purchaseTotals.taxAmount,
    };
  }

  async getAnnualReport(userId: number, year: number) {
    const [profitLoss, taxSummary] = await Promise.all([
      this.getProfitLoss(userId, year),
      this.getTaxSummary(userId, year),
    ]);

    return {
      year,
      revenue: {
        total: profitLoss.totalRevenue,
        monthly: profitLoss.monthly.map((m) => ({
          month: m.month,
          amount: m.revenue,
        })),
      },
      expenses: {
        total: profitLoss.totalExpenses,
        monthly: profitLoss.monthly.map((m) => ({
          month: m.month,
          amount: m.expenses,
        })),
      },
      profit: {
        total: profitLoss.totalProfit,
        monthly: profitLoss.monthly.map((m) => ({
          month: m.month,
          amount: m.profit,
        })),
      },
      tax: taxSummary,
    };
  }
}
