import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Cron } from '@nestjs/schedule';
import { UserAccount } from '@/entities/user-account.entity';
import { MerchantAccount } from '@/entities/merchant-account.entity';
import { PlatformAccount } from '@/entities/platform-account.entity';
import { UserTransaction } from '@/entities/user-transaction.entity';
import { MerchantTransaction } from '@/entities/merchant-transaction.entity';
import { PlatformTransaction } from '@/entities/platform-transaction.entity';
import { DailyReconciliation } from '@/entities/daily-reconciliation.entity';
import { Order } from '@/entities/order.entity';
import { Settlement } from '@/entities/settlement.entity';
import { UserWithdrawal } from '@/entities/user-withdrawal.entity';
import { MerchantWithdrawal } from '@/entities/merchant-withdrawal.entity';
import { PlatformWithdrawal } from '@/entities/platform-withdrawal.entity';
import dayjs from 'dayjs';

@Injectable()
export class ReconciliationService {
  private readonly logger = new Logger(ReconciliationService.name);

  constructor(
    @InjectRepository(UserAccount)
    private userAccountRepo: Repository<UserAccount>,
    @InjectRepository(MerchantAccount)
    private merchantAccountRepo: Repository<MerchantAccount>,
    @InjectRepository(PlatformAccount)
    private platformAccountRepo: Repository<PlatformAccount>,
    @InjectRepository(UserTransaction)
    private userTransactionRepo: Repository<UserTransaction>,
    @InjectRepository(MerchantTransaction)
    private merchantTransactionRepo: Repository<MerchantTransaction>,
    @InjectRepository(PlatformTransaction)
    private platformTransactionRepo: Repository<PlatformTransaction>,
    @InjectRepository(DailyReconciliation)
    private reconciliationRepo: Repository<DailyReconciliation>,
    @InjectRepository(Order)
    private orderRepo: Repository<Order>,
    @InjectRepository(Settlement)
    private settlementRepo: Repository<Settlement>,
    @InjectRepository(UserWithdrawal)
    private userWithdrawalRepo: Repository<UserWithdrawal>,
    @InjectRepository(MerchantWithdrawal)
    private merchantWithdrawalRepo: Repository<MerchantWithdrawal>,
    @InjectRepository(PlatformWithdrawal)
    private platformWithdrawalRepo: Repository<PlatformWithdrawal>,
  ) {}

  /**
   * 每天凌晨3点自动执行日对账
   */
  @Cron('0 3 * * *')
  async handleDailyReconciliation() {
    this.logger.log('开始执行日对账任务');

    try {
      const yesterday = dayjs().subtract(1, 'day').format('YYYY-MM-DD');
      await this.performReconciliation(yesterday);
      this.logger.log('日对账任务执行完成');
    } catch (error) {
      this.logger.error(`日对账任务执行失败：${error.message}`);
    }
  }

  /**
   * 执行对账
   */
  async performReconciliation(date: string) {
    const platformAccount = await this.platformAccountRepo.findOne({
      where: { account_name: '主账户' }
    });

    const platformBalanceStart = Number(platformAccount?.balance || 0);

    const orderCount = await this.orderRepo.count({
      where: {
        createdAt: dayjs(date).toDate() as any
      }
    });

    const orders = await this.orderRepo.find({
      where: {
        createdAt: dayjs(date).toDate() as any
      }
    });

    const totalOrderAmount = orders.reduce((sum, o) => sum + Number(o.payAmount || 0), 0);
    const totalServiceFee = 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 totalSettlement = settlements.reduce((sum, s) => sum + Number(s.settlementAmount || 0), 0);

    const userWithdrawals = await this.userWithdrawalRepo
      .createQueryBuilder('w')
      .where('DATE(w.paidAt) = :date', { date })
      .andWhere('w.status = :status', { status: 'paid' })
      .getMany();

    const merchantWithdrawals = await this.merchantWithdrawalRepo
      .createQueryBuilder('w')
      .where('DATE(w.paidAt) = :date', { date })
      .andWhere('w.status = :status', { status: 'paid' })
      .getMany();

    const platformWithdrawals = await this.platformWithdrawalRepo
      .createQueryBuilder('w')
      .where('DATE(w.paidAt) = :date', { date })
      .andWhere('w.status = :status', { status: 'paid' })
      .getMany();

    const withdrawCount = userWithdrawals.length + merchantWithdrawals.length + platformWithdrawals.length;
    const totalWithdraw =
      userWithdrawals.reduce((sum, w) => sum + Number(w.actualAmount || 0), 0) +
      merchantWithdrawals.reduce((sum, w) => sum + Number(w.actualAmount || 0), 0) +
      platformWithdrawals.reduce((sum, w) => sum + Number(w.actualAmount || 0), 0);

    const totalCashback = await this.sumPlatformTransactionsByType(date, '邀请返现');

    const platformBalanceEnd = Number(platformAccount?.balance || 0);

    const reconciliation = this.reconciliationRepo.create({
      reconciliationDate: new Date(date),
      totalOrderAmount,
      totalServiceFee,
      totalCashback,
      totalSettlement,
      totalWithdraw,
      platformBalanceStart,
      platformBalanceEnd,
      orderCount,
      settlementCount,
      withdrawCount,
      status: 'completed',
      remark: `${date} 日对账完成`
    });

    await this.reconciliationRepo.save(reconciliation);

    this.logger.log(`对账完成：订单${orderCount}笔，结算${settlementCount}笔，提现${withdrawCount}笔`);

    return reconciliation;
  }

  /**
   * 按交易类型统计平台交易金额
   */
  private async sumPlatformTransactionsByType(date: string, transactionType: string): Promise<number> {
    const result = await this.platformTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('DATE(t.createdAt) = :date', { date })
      .andWhere('t.transactionType = :type', { type: transactionType })
      .getRawOne();

    return Number(result?.sum || 0);
  }

  /**
   * 手动执行对账（管理员操作）
   */
  async manualReconciliation(date: string) {
    return await this.performReconciliation(date);
  }

  /**
   * 获取对账记录列表
   */
  async getReconciliations(params: {
    status?: 'pending' | 'completed' | 'failed';
    startDate?: string;
    endDate?: string;
    page?: number;
    pageSize?: number;
  }) {
    const { status, startDate, endDate, page = 1, pageSize = 20 } = params;

    const queryBuilder = this.reconciliationRepo.createQueryBuilder('r');

    if (status) {
      queryBuilder.andWhere('r.status = :status', { status });
    }

    if (startDate && endDate) {
      queryBuilder.andWhere('r.reconciliationDate BETWEEN :startDate AND :endDate', {
        startDate,
        endDate
      });
    }

    queryBuilder.orderBy('r.reconciliationDate', 'DESC');
    queryBuilder.skip((page - 1) * pageSize).take(pageSize);

    const [list, total] = await queryBuilder.getManyAndCount();

    return {
      list: list.map(item => ({
        ...item,
        totalOrderAmount: Number(item.totalOrderAmount),
        totalServiceFee: Number(item.totalServiceFee),
        totalCashback: Number(item.totalCashback),
        totalSettlement: Number(item.totalSettlement),
        totalWithdraw: Number(item.totalWithdraw),
        platformBalanceStart: Number(item.platformBalanceStart),
        platformBalanceEnd: Number(item.platformBalanceEnd)
      })),
      total,
      page,
      pageSize,
      totalPages: Math.ceil(total / pageSize)
    };
  }

  /**
   * 获取账户余额汇总
   */
  async getAccountSummary() {
    const platformAccount = await this.platformAccountRepo.findOne({
      where: { account_name: '主账户' }
    });

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

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

    return {
      platform: {
        balance: Number(platformAccount?.balance || 0),
        frozenBalance: Number(platformAccount?.frozen_balance || 0),
        count: 1
      },
      merchant: {
        balance: Number(merchantStats?.balance || 0),
        frozenBalance: Number(merchantStats?.frozenBalance || 0),
        count: Number(merchantStats?.count || 0)
      },
      user: {
        balance: Number(userStats?.balance || 0),
        frozenBalance: Number(userStats?.frozenBalance || 0),
        count: Number(userStats?.count || 0)
      },
      total: {
        balance: Number(platformAccount?.balance || 0) +
                Number(merchantStats?.balance || 0) +
                Number(userStats?.balance || 0),
        frozenBalance: Number(platformAccount?.frozen_balance || 0) +
                       Number(merchantStats?.frozenBalance || 0) +
                       Number(userStats?.frozenBalance || 0)
      }
    };
  }

  /**
   * 获取用户交易统计
   */
  async getUserTransactionStats(params: {
    startDate: string;
    endDate: string;
  }) {
    const { startDate, endDate } = params;

    const stats = await this.userTransactionRepo
      .createQueryBuilder('t')
      .select('t.transactionType', 'type')
      .addSelect('t.direction', 'direction')
      .addSelect('SUM(t.amount)', 'total')
      .addSelect('COUNT(*)', 'count')
      .where('DATE(t.createdAt) BETWEEN :startDate AND :endDate', { startDate, endDate })
      .groupBy('t.transactionType')
      .addGroupBy('t.direction')
      .getRawMany();

    return stats.map(item => ({
      type: item.type,
      direction: item.direction,
      total: Number(item.total),
      count: Number(item.count)
    }));
  }

  /**
   * 获取商家交易统计
   */
  async getMerchantTransactionStats(params: {
    startDate: string;
    endDate: string;
  }) {
    const { startDate, endDate } = params;

    const stats = await this.merchantTransactionRepo
      .createQueryBuilder('t')
      .select('t.transactionType', 'type')
      .addSelect('t.direction', 'direction')
      .addSelect('SUM(t.amount)', 'total')
      .addSelect('COUNT(*)', 'count')
      .where('DATE(t.createdAt) BETWEEN :startDate AND :endDate', { startDate, endDate })
      .groupBy('t.transactionType')
      .addGroupBy('t.direction')
      .getRawMany();

    return stats.map(item => ({
      type: item.type,
      direction: item.direction,
      total: Number(item.total),
      count: Number(item.count)
    }));
  }

  /**
   * 获取平台交易统计
   */
  async getPlatformTransactionStats(params: {
    startDate: string;
    endDate: string;
  }) {
    const { startDate, endDate } = params;

    const stats = await this.platformTransactionRepo
      .createQueryBuilder('t')
      .select('t.transactionType', 'type')
      .addSelect('t.direction', 'direction')
      .addSelect('SUM(t.amount)', 'total')
      .addSelect('COUNT(*)', 'count')
      .where('DATE(t.createdAt) BETWEEN :startDate AND :endDate', { startDate, endDate })
      .groupBy('t.transactionType')
      .addGroupBy('t.direction')
      .getRawMany();

    return stats.map(item => ({
      type: item.type,
      direction: item.direction,
      total: Number(item.total),
      count: Number(item.count)
    }));
  }

  /**
   * 检查用户账户余额一致性
   */
  async checkUserAccountConsistency(userId: number) {
    const account = await this.userAccountRepo.findOne({ where: { user_id: userId } });

    if (!account) {
      throw new Error('用户账户不存在');
    }

    const incomeSum = await this.userTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('t.accountId = :accountId', { accountId: account.id })
      .andWhere('t.direction = :direction', { direction: 'income' })
      .getRawOne();

    const expenseSum = await this.userTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('t.accountId = :accountId', { accountId: account.id })
      .andWhere('t.direction = :direction', { direction: 'expense' })
      .getRawOne();

    const calculatedBalance = Number(incomeSum?.sum || 0) - Number(expenseSum?.sum || 0);
    const actualBalance = Number(account.balance) + Number(account.frozen_balance);
    const difference = Math.abs(calculatedBalance - actualBalance);

    const isConsistent = difference < 0.01;

    return {
      accountId: account.id,
      userId,
      actualBalance: Number(account.balance),
      frozenBalance: Number(account.frozen_balance),
      calculatedBalance,
      difference,
      isConsistent,
      totalIncome: Number(account.total_income),
      totalExpense: Number(account.total_expense)
    };
  }

  /**
   * 检查商家账户余额一致性
   */
  async checkMerchantAccountConsistency(merchantId: number) {
    const account = await this.merchantAccountRepo.findOne({ where: { merchant_id: merchantId } });

    if (!account) {
      throw new Error('商家账户不存在');
    }

    const incomeSum = await this.merchantTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('t.accountId = :accountId', { accountId: account.id })
      .andWhere('t.direction = :direction', { direction: 'income' })
      .getRawOne();

    const expenseSum = await this.merchantTransactionRepo
      .createQueryBuilder('t')
      .select('SUM(t.amount)', 'sum')
      .where('t.accountId = :accountId', { accountId: account.id })
      .andWhere('t.direction = :direction', { direction: 'expense' })
      .getRawOne();

    const calculatedBalance = Number(incomeSum?.sum || 0) - Number(expenseSum?.sum || 0);
    const actualBalance = Number(account.balance) + Number(account.frozen_balance);
    const difference = Math.abs(calculatedBalance - actualBalance);

    const isConsistent = difference < 0.01;

    return {
      accountId: account.id,
      merchantId,
      actualBalance: Number(account.balance),
      frozenBalance: Number(account.frozen_balance),
      debtAmount: Number(account.debt_amount),
      calculatedBalance,
      difference,
      isConsistent,
      totalIncome: Number(account.total_income),
      totalExpense: Number(account.total_expense)
    };
  }
}
