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

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

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

  async getOverview(userId: number) {
    const now = new Date();
    const yearStart = new Date(now.getFullYear(), 0, 1);
    const yearEnd = new Date(now.getFullYear(), 11, 31, 23, 59, 59, 999);

    const [
      paidSettlements,
      totalExpensesResult,
      outstandingSettlements,
      activeProjectsCount,
      recentSettlements,
      upcomingSettlements,
    ] = await Promise.all([
      // Total revenue: paid settlements this year
      this.prisma.settlement.findMany({
        where: {
          userId,
          paymentStatus: 'paid',
          settlementDate: {
            gte: yearStart,
            lte: yearEnd,
          },
        },
        select: { totalAmount: true },
      }),
      // Total expenses this year
      this.prisma.expense.aggregate({
        where: {
          userId,
          expenseDate: {
            gte: yearStart,
            lte: yearEnd,
          },
        },
        _sum: { amount: true },
      }),
      // Outstanding settlements (not paid)
      this.prisma.settlement.findMany({
        where: {
          userId,
          paymentStatus: { not: 'paid' },
        },
        select: { totalAmount: true },
      }),
      // Active projects count
      this.prisma.project.count({
        where: {
          userId,
          status: {
            notIn: ['payment-completed', 'cancelled'],
          },
        },
      }),
      // Recent settlements (5)
      this.prisma.settlement.findMany({
        where: { userId },
        orderBy: { settlementDate: 'desc' },
        take: 5,
        include: {
          client: {
            select: { id: true, name: true, nameEn: true },
          },
          project: {
            select: { id: true, name: true, nameEn: true },
          },
        },
      }),
      // Upcoming settlements (5) - future or pending
      this.prisma.settlement.findMany({
        where: {
          userId,
          paymentStatus: { not: 'paid' },
          settlementDate: {
            gte: new Date(),
          },
        },
        orderBy: { settlementDate: 'asc' },
        take: 5,
        include: {
          client: {
            select: { id: true, name: true, nameEn: true },
          },
          project: {
            select: { id: true, name: true, nameEn: true },
          },
        },
      }),
    ]);

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

    const totalExpenses = totalExpensesResult._sum.amount || BigInt(0);

    const outstandingTotal = outstandingSettlements.reduce(
      (sum, s) => sum + s.totalAmount,
      BigInt(0),
    );

    return this.serializeBigInt({
      totalRevenue: Number(totalRevenue),
      totalExpenses: Number(totalExpenses),
      outstandingSettlements: Number(outstandingTotal),
      activeProjectsCount,
      recentSettlements,
      upcomingSettlements,
    });
  }

  async getRecentActivity(userId: number) {
    const [recentSettlements, recentEstimates, recentContracts] =
      await Promise.all([
        this.prisma.settlement.findMany({
          where: { userId },
          orderBy: { createdAt: 'desc' },
          take: 10,
          select: {
            id: true,
            settlementNumber: true,
            totalAmount: true,
            paymentStatus: true,
            settlementDate: true,
            createdAt: true,
            client: {
              select: { id: true, name: true, nameEn: true },
            },
          },
        }),
        this.prisma.estimate.findMany({
          where: { userId },
          orderBy: { createdAt: 'desc' },
          take: 10,
          select: {
            id: true,
            estimateNumber: true,
            totalAmount: true,
            status: true,
            issueDate: true,
            createdAt: true,
            client: {
              select: { id: true, name: true, nameEn: true },
            },
          },
        }),
        this.prisma.contract.findMany({
          where: { userId },
          orderBy: { createdAt: 'desc' },
          take: 10,
          select: {
            id: true,
            contractNumber: true,
            totalAmount: true,
            status: true,
            startDate: true,
            createdAt: true,
            client: {
              select: { id: true, name: true, nameEn: true },
            },
          },
        }),
      ]);

    // Combine and sort by createdAt, take 10
    const activities = [
      ...recentSettlements.map((s) => ({
        type: 'settlement' as const,
        id: s.id,
        number: s.settlementNumber,
        amount: s.totalAmount,
        status: s.paymentStatus,
        date: s.settlementDate,
        createdAt: s.createdAt,
        client: s.client,
      })),
      ...recentEstimates.map((e) => ({
        type: 'estimate' as const,
        id: e.id,
        number: e.estimateNumber,
        amount: e.totalAmount,
        status: e.status,
        date: e.issueDate,
        createdAt: e.createdAt,
        client: e.client,
      })),
      ...recentContracts.map((c) => ({
        type: 'contract' as const,
        id: c.id,
        number: c.contractNumber,
        amount: c.totalAmount,
        status: c.status,
        date: c.startDate,
        createdAt: c.createdAt,
        client: c.client,
      })),
    ];

    activities.sort(
      (a, b) =>
        new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
    );

    return this.serializeBigInt(activities.slice(0, 10));
  }

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

    const [settlements, expenses] = await Promise.all([
      this.prisma.settlement.findMany({
        where: {
          userId,
          paymentStatus: 'paid',
          settlementDate: {
            gte: startDate,
            lte: endDate,
          },
        },
        select: {
          totalAmount: true,
          settlementDate: true,
        },
      }),
      this.prisma.expense.findMany({
        where: {
          userId,
          expenseDate: {
            gte: startDate,
            lte: endDate,
          },
        },
        select: {
          amount: true,
          expenseDate: true,
        },
      }),
    ]);

    const monthly: {
      month: number;
      revenue: number;
      expenses: number;
    }[] = [];

    for (let m = 1; m <= 12; m++) {
      const monthRevenue = settlements
        .filter((s) => new Date(s.settlementDate).getMonth() + 1 === m)
        .reduce((sum, s) => sum + s.totalAmount, BigInt(0));

      const monthExpenses = expenses
        .filter((e) => new Date(e.expenseDate).getMonth() + 1 === m)
        .reduce((sum, e) => sum + e.amount, BigInt(0));

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

    return {
      year,
      monthly,
    };
  }
}
