import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { PlatformAccount } from '@/entities/platform-account.entity';
import { UserAccount } from '@/entities/user-account.entity';
import { MerchantAccount } from '@/entities/merchant-account.entity';
import { PlatformTransaction } from '@/entities/platform-transaction.entity';
import { Order } from '@/entities/order.entity';
import { Settlement } from '@/entities/settlement.entity';
import dayjs from 'dayjs';

@Injectable()
export class ReportService {
  constructor(
    @InjectRepository(PlatformAccount)
    private platformAccountRepo: Repository<PlatformAccount>,
    @InjectRepository(UserAccount)
    private userAccountRepo: Repository<UserAccount>,
    @InjectRepository(MerchantAccount)
    private merchantAccountRepo: Repository<MerchantAccount>,
    @InjectRepository(PlatformTransaction)
    private platformTransactionRepo: Repository<PlatformTransaction>,
    @InjectRepository(Order)
    private orderRepo: Repository<Order>,
    @InjectRepository(Settlement)
    private settlementRepo: Repository<Settlement>,
  ) {}

  /**
   * 财务总览
   */
  async getOverview() {
    const platformAccount = await this.platformAccountRepo.findOne({
      where: { account_name: '主账户' },
    });

    const merchantStats = await this.merchantAccountRepo
      .createQueryBuilder('a')
      .select('SUM(a.balance)', 'totalBalance')
      .addSelect('COUNT(*)', 'count')
      .getRawOne();

    const userStats = await this.userAccountRepo
      .createQueryBuilder('a')
      .select('SUM(a.balance)', 'totalBalance')
      .addSelect('COUNT(*)', 'count')
      .getRawOne();

    const today = dayjs().format('YYYY-MM-DD');
    const todayOrders = await this.orderRepo.count({
      where: {
        createdAt: dayjs(today).toDate() as any,
      },
    });

    const todayIncome = await this.platformTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('DATE(t.created_at) = :date', { date: today })
      .andWhere('t.direction = :direction', { direction: 'income' })
      .getRawOne();

    const todayExpense = await this.platformTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('DATE(t.created_at) = :date', { date: today })
      .andWhere('t.direction = :direction', { direction: 'expense' })
      .getRawOne();

    return {
      platformBalance: Number(platformAccount?.balance || 0),
      merchantTotalBalance: Number(merchantStats?.totalBalance || 0),
      merchantCount: Number(merchantStats?.count || 0),
      userTotalBalance: Number(userStats?.totalBalance || 0),
      userCount: Number(userStats?.count || 0),
      todayOrders,
      todayIncome: Number(todayIncome?.sum || 0),
      todayExpense: Number(todayExpense?.sum || 0),
    };
  }

  /**
   * 财务趋势（按日统计）
   */
  async getTrend(params: { startDate: string; endDate: string }) {
    const { startDate, endDate } = params;

    const transactions = await this.platformTransactionRepo
      .createQueryBuilder('t')
      .select('DATE(t.created_at)', 'date')
      .addSelect('t.direction', 'direction')
      .addSelect('SUM(t.amount)', 'amount')
      .where('DATE(t.created_at) BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      })
      .groupBy('DATE(t.created_at)')
      .addGroupBy('t.direction')
      .orderBy('DATE(t.created_at)', 'ASC')
      .getRawMany();

    const orders = await this.orderRepo
      .createQueryBuilder('o')
      .select('DATE(o.createdAt)', 'date')
      .addSelect('COUNT(*)', 'count')
      .where('DATE(o.createdAt) BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      })
      .groupBy('DATE(o.createdAt)')
      .orderBy('DATE(o.createdAt)', 'ASC')
      .getRawMany();

    const dateMap = new Map<string, { income: number; expense: number; orderCount: number }>();

    transactions.forEach((item) => {
      const date = item.date;
      if (!dateMap.has(date)) {
        dateMap.set(date, { income: 0, expense: 0, orderCount: 0 });
      }
      const data = dateMap.get(date)!;
      if (item.direction === 'income') {
        data.income = Number(item.amount);
      } else {
        data.expense = Number(item.amount);
      }
    });

    orders.forEach((item) => {
      const date = item.date;
      if (!dateMap.has(date)) {
        dateMap.set(date, { income: 0, expense: 0, orderCount: 0 });
      }
      const data = dateMap.get(date)!;
      data.orderCount = Number(item.count);
    });

    const result = Array.from(dateMap.entries()).map(([date, data]) => ({
      date,
      income: data.income,
      expense: data.expense,
      orderCount: data.orderCount,
      net: data.income - data.expense,
    }));

    return result;
  }

  /**
   * 日报表
   */
  async getDailyReport(date: string) {
    const orders = await this.orderRepo
      .createQueryBuilder('o')
      .where('DATE(o.createdAt) = :date', { date })
      .getMany();

    const orderCount = orders.length;
    const orderAmount = orders.reduce((sum, o) => sum + Number(o.payAmount || 0), 0);
    const serviceFee = orders.reduce((sum, o) => sum + Number(o.serviceFee || 0), 0);

    const settlements = await this.settlementRepo
      .createQueryBuilder('s')
      .where('DATE(s.settledAt) = :date', { date })
      .getMany();

    const settlementCount = settlements.length;
    const settlementAmount = settlements.reduce(
      (sum, s) => sum + Number(s.settlementAmount || 0),
      0,
    );

    const income = await this.platformTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('DATE(t.created_at) = :date', { date })
      .andWhere('t.direction = :direction', { direction: 'income' })
      .getRawOne();

    const expense = await this.platformTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('DATE(t.created_at) = :date', { date })
      .andWhere('t.direction = :direction', { direction: 'expense' })
      .getRawOne();

    return {
      date,
      orderCount,
      orderAmount,
      serviceFee,
      settlementCount,
      settlementAmount,
      totalIncome: Number(income?.sum || 0),
      totalExpense: Number(expense?.sum || 0),
      netAmount: Number(income?.sum || 0) - Number(expense?.sum || 0),
    };
  }

  /**
   * 周报表
   */
  async getWeeklyReport(params: { startDate: string; endDate: string }) {
    return this.getPeriodReport(params.startDate, params.endDate);
  }

  /**
   * 月报表
   */
  async getMonthlyReport(params: { year: number; month: number }) {
    const { year, month } = params;
    const startDate = dayjs(`${year}-${month}-01`).format('YYYY-MM-DD');
    const endDate = dayjs(startDate).endOf('month').format('YYYY-MM-DD');

    return this.getPeriodReport(startDate, endDate);
  }

  /**
   * 周期报表（通用）
   */
  private async getPeriodReport(startDate: string, endDate: string) {
    const orders = await this.orderRepo
      .createQueryBuilder('o')
      .where('DATE(o.createdAt) BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      })
      .getMany();

    const orderCount = orders.length;
    const orderAmount = orders.reduce((sum, o) => sum + Number(o.payAmount || 0), 0);
    const serviceFee = orders.reduce((sum, o) => sum + Number(o.serviceFee || 0), 0);

    const settlements = await this.settlementRepo
      .createQueryBuilder('s')
      .where('DATE(s.settledAt) BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      })
      .getMany();

    const settlementCount = settlements.length;
    const settlementAmount = settlements.reduce(
      (sum, s) => sum + Number(s.settlementAmount || 0),
      0,
    );

    const income = await this.platformTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('DATE(t.created_at) BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      })
      .andWhere('t.direction = :direction', { direction: 'income' })
      .getRawOne();

    const expense = await this.platformTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('DATE(t.created_at) BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      })
      .andWhere('t.direction = :direction', { direction: 'expense' })
      .getRawOne();

    return {
      startDate,
      endDate,
      orderCount,
      orderAmount,
      serviceFee,
      settlementCount,
      settlementAmount,
      totalIncome: Number(income?.sum || 0),
      totalExpense: Number(expense?.sum || 0),
      netAmount: Number(income?.sum || 0) - Number(expense?.sum || 0),
    };
  }
}
