import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { SystemAccount } from '@/entities/system-account.entity';
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 { MerchantWithdrawal } from '@/entities/merchant-withdrawal.entity';
import { UserWithdrawal } from '@/entities/user-withdrawal.entity';
import { PlatformWithdrawal } from '@/entities/platform-withdrawal.entity';
import { MktInviteWithdrawal } from '@/entities/mkt-invite-withdrawal.entity';
import { ACCOUNT_NAMES } from '@/constants/account.constant';
import dayjs from 'dayjs';

@Injectable()
export class ReportService {
  constructor(
    @InjectRepository(SystemAccount)
    private systemAccountRepo: Repository<SystemAccount>,
    @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>,
    @InjectRepository(MerchantWithdrawal)
    private merchantWithdrawalRepo: Repository<MerchantWithdrawal>,
    @InjectRepository(UserWithdrawal)
    private userWithdrawalRepo: Repository<UserWithdrawal>,
    @InjectRepository(PlatformWithdrawal)
    private platformWithdrawalRepo: Repository<PlatformWithdrawal>,
    @InjectRepository(MktInviteWithdrawal)
    private mktInviteWithdrawalRepo: Repository<MktInviteWithdrawal>,
  ) {}

  /**
   * 财务总览
   */
  async getOverview() {
    // 获取系统总账户
    const systemAccount = await this.systemAccountRepo.findOne({
      where: { account_name: ACCOUNT_NAMES.SYSTEM_MAIN },
    });

    // 获取平台账户
    const platformAccount = await this.platformAccountRepo.findOne({
      where: { account_name: ACCOUNT_NAMES.PLATFORM_MAIN },
    });

    const merchantStats = await this.merchantAccountRepo
      .createQueryBuilder('a')
      .select('SUM(a.balance)', 'totalBalance')
      .addSelect('SUM(a.pending_settlement)', 'totalPendingSettlement')
      .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();

    // 系统总账户金额（直接从数据库读取）
    const systemTotalAmount = Number(systemAccount?.balance || 0);

    // 各层级账户余额
    const totalMerchantBalance = Number(merchantStats?.totalBalance || 0);
    const totalMerchantPendingSettlement = Number(merchantStats?.totalPendingSettlement || 0);
    const totalUserBalance = Number(userStats?.totalBalance || 0);
    const platformBalance = Number(platformAccount?.balance || 0);

    return {
      // 系统总账户金额（从 system_accounts 表读取）
      systemTotalAmount,
      totalUserPaid: Number(systemAccount?.total_income || 0),
      totalRefund: Number(systemAccount?.total_refund || 0),
      totalWithdrawn: Number(systemAccount?.total_withdrawn || 0),

      // 平台净收益（服务费 - 邀请返现）
      platformBalance,
      platformTotalIncome: Number(platformAccount?.total_income || 0),
      platformTotalExpense: Number(platformAccount?.total_expense || 0),

      // 商家账户统计
      totalMerchantBalance,
      totalMerchantPendingSettlement,
      merchantCount: Number(merchantStats?.count || 0),

      // 用户账户统计
      totalUserBalance,
      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),
    };
  }

  /**
   * 服务费统计
   */
  async getServiceFeeStatistics() {
    const today = dayjs().format('YYYY-MM-DD');
    const monthStart = dayjs().startOf('month').format('YYYY-MM-DD');
    const monthEnd = dayjs().endOf('month').format('YYYY-MM-DD');

    // 今日服务费
    const todayFee = await this.orderRepo
      .createQueryBuilder('o')
      .select('SUM(o.service_fee)', 'sum')
      .where('DATE(o.created_at) = :date', { date: today })
      .andWhere('o.status != :status', { status: 'cancelled' })
      .getRawOne();

    // 本月服务费
    const monthFee = await this.orderRepo
      .createQueryBuilder('o')
      .select('SUM(o.service_fee)', 'sum')
      .where('DATE(o.created_at) BETWEEN :start AND :end', {
        start: monthStart,
        end: monthEnd,
      })
      .andWhere('o.status != :status', { status: 'cancelled' })
      .getRawOne();

    // 累计服务费
    const totalFee = await this.orderRepo
      .createQueryBuilder('o')
      .select('SUM(o.service_fee)', 'sum')
      .where('o.status != :status', { status: 'cancelled' })
      .getRawOne();

    // 待结算服务费（已完成但未结算的订单）
    const pendingFee = await this.orderRepo
      .createQueryBuilder('o')
      .leftJoin('settlement_items', 'si', 'si.order_id = o.id')
      .select('SUM(o.service_fee)', 'sum')
      .where('o.status = :status', { status: 'completed' })
      .andWhere('si.id IS NULL')
      .getRawOne();

    return {
      todayCommission: Number(todayFee?.sum || 0),
      monthCommission: Number(monthFee?.sum || 0),
      totalCommission: Number(totalFee?.sum || 0),
      pendingCommission: Number(pendingFee?.sum || 0),
    };
  }

  /**
   * 服务费明细列表
   */
  async getServiceFeeList(params: {
    page: number;
    pageSize: number;
    startDate?: string;
    endDate?: string;
  }) {
    const { page, pageSize, startDate, endDate } = params;

    const query = this.orderRepo
      .createQueryBuilder('o')
      .leftJoinAndSelect('o.merchant', 'm')
      .leftJoinAndSelect('o.user', 'u')
      .leftJoin('settlement_items', 'si', 'si.order_id = o.id')
      .leftJoin('settlements', 's', 's.id = si.settlement_id')
      .select([
        'o.id',
        'o.orderNo',
        'o.totalAmount',
        'o.serviceFee',
        'o.status',
        'o.createdAt',
        'm.id',
        'm.shopName',
        'u.id',
        'u.nickname',
        's.settledAt',
      ])
      .where('o.status != :status', { status: 'cancelled' })
      .andWhere('o.service_fee > 0');

    if (startDate && endDate) {
      query.andWhere('DATE(o.created_at) BETWEEN :startDate AND :endDate', {
        startDate,
        endDate,
      });
    }

    const [list, total] = await query
      .orderBy('o.created_at', 'DESC')
      .skip((page - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

    const result = list.map((order) => ({
      id: order.id,
      orderId: order.id,
      orderNo: order.orderNo,
      merchantName: order.merchant?.shopName || '-',
      userName: order.user?.nickname || '-',
      orderAmount: Number(order.totalAmount),
      commissionRate: 0.05, // 固定5%，如果需要动态获取可以从配置读取
      commissionAmount: Number(order.serviceFee),
      status: order['s_settledAt'] ? 'settled' : 'pending',
      settledAt: order['s_settledAt'] || null,
      createdAt: order.createdAt,
    }));

    return {
      list: result,
      total,
      page,
      pageSize,
    };
  }
}
