import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { PrismaService } from '../../infrastructure/persistence/prisma/prisma.service';
import Decimal from 'decimal.js';

@Injectable()
export class DailyReportService implements OnModuleInit {
  private readonly logger = new Logger(DailyReportService.name);
  private reportInterval: NodeJS.Timeout | null = null;

  constructor(private readonly prisma: PrismaService) {}

  async onModuleInit() {
    // 启动时先生成一次报表
    await this.generateTodayReport();

    // 每小时检查并更新当日报表
    this.reportInterval = setInterval(
      () => this.generateTodayReport(),
      60 * 60 * 1000, // 1 hour
    );

    this.logger.log('Daily report service initialized');
  }

  /**
   * 生成或更新今日报表
   */
  async generateTodayReport(): Promise<void> {
    const today = new Date();
    today.setHours(0, 0, 0, 0);

    try {
      this.logger.log(`Generating daily report for ${today.toISOString().split('T')[0]}`);

      // 收集各项统计数据
      const [
        userStats,
        adoptionStats,
        contributionStats,
        miningStats,
        tradingStats,
        priceStats,
      ] = await Promise.all([
        this.getUserStats(today),
        this.getAdoptionStats(today),
        this.getContributionStats(today),
        this.getMiningStats(),
        this.getTradingStats(today),
        this.getPriceStats(today),
      ]);

      // 更新或创建今日报表
      await this.prisma.dailyReport.upsert({
        where: { reportDate: today },
        create: {
          reportDate: today,
          ...userStats,
          ...adoptionStats,
          ...contributionStats,
          ...miningStats,
          ...tradingStats,
          ...priceStats,
        },
        update: {
          ...userStats,
          ...adoptionStats,
          ...contributionStats,
          ...miningStats,
          ...tradingStats,
          ...priceStats,
        },
      });

      this.logger.log(`Daily report generated successfully for ${today.toISOString().split('T')[0]}`);
    } catch (error) {
      this.logger.error('Failed to generate daily report', error);
    }
  }

  /**
   * 生成历史报表（用于补数据）
   */
  async generateHistoricalReport(date: Date): Promise<void> {
    const reportDate = new Date(date);
    reportDate.setHours(0, 0, 0, 0);

    const [
      userStats,
      adoptionStats,
      contributionStats,
      miningStats,
      tradingStats,
      priceStats,
    ] = await Promise.all([
      this.getUserStats(reportDate),
      this.getAdoptionStats(reportDate),
      this.getContributionStats(reportDate),
      this.getMiningStats(),
      this.getTradingStats(reportDate),
      this.getPriceStats(reportDate),
    ]);

    await this.prisma.dailyReport.upsert({
      where: { reportDate },
      create: {
        reportDate,
        ...userStats,
        ...adoptionStats,
        ...contributionStats,
        ...miningStats,
        ...tradingStats,
        ...priceStats,
      },
      update: {
        ...userStats,
        ...adoptionStats,
        ...contributionStats,
        ...miningStats,
        ...tradingStats,
        ...priceStats,
      },
    });
  }

  /**
   * 用户统计
   */
  private async getUserStats(date: Date) {
    const nextDay = new Date(date);
    nextDay.setDate(nextDay.getDate() + 1);

    const [totalUsers, newUsers] = await Promise.all([
      this.prisma.syncedUser.count({
        where: { createdAt: { lt: nextDay } },
      }),
      this.prisma.syncedUser.count({
        where: {
          createdAt: { gte: date, lt: nextDay },
        },
      }),
    ]);

    // 活跃用户暂时用总用户数（需要有活跃度跟踪才能准确计算）
    const activeUsers = totalUsers;

    return {
      totalUsers,
      newUsers,
      activeUsers,
    };
  }

  /**
   * 认种统计
   */
  private async getAdoptionStats(date: Date) {
    const nextDay = new Date(date);
    nextDay.setDate(nextDay.getDate() + 1);

    const [totalAdoptions, newAdoptions, treesResult] = await Promise.all([
      this.prisma.syncedAdoption.count({
        where: { adoptionDate: { lt: nextDay } },
      }),
      this.prisma.syncedAdoption.count({
        where: {
          adoptionDate: { gte: date, lt: nextDay },
        },
      }),
      this.prisma.syncedAdoption.aggregate({
        where: { adoptionDate: { lt: nextDay } },
        _sum: { treeCount: true },
      }),
    ]);

    return {
      totalAdoptions,
      newAdoptions,
      totalTrees: treesResult._sum.treeCount || 0,
    };
  }

  /**
   * 算力统计
   */
  private async getContributionStats(date: Date) {
    // 获取全网算力进度
    const networkProgress = await this.prisma.syncedNetworkProgress.findFirst();

    // 获取用户算力汇总
    const userContribution = await this.prisma.syncedContributionAccount.aggregate({
      _sum: {
        totalContribution: true,
        effectiveContribution: true,
      },
    });

    const totalContribution = new Decimal(
      userContribution._sum.totalContribution?.toString() || '0',
    );

    // 获取昨日报表计算增长
    const yesterday = new Date(date);
    yesterday.setDate(yesterday.getDate() - 1);
    const yesterdayReport = await this.prisma.dailyReport.findUnique({
      where: { reportDate: yesterday },
    });

    const contributionGrowth = yesterdayReport
      ? totalContribution.minus(new Decimal(yesterdayReport.totalContribution.toString()))
      : totalContribution;

    return {
      totalContribution,
      contributionGrowth: contributionGrowth.gt(0) ? contributionGrowth : new Decimal(0),
    };
  }

  /**
   * 挖矿统计
   */
  private async getMiningStats() {
    const dailyStat = await this.prisma.syncedDailyMiningStat.findFirst({
      orderBy: { statDate: 'desc' },
    });

    return {
      totalDistributed: dailyStat?.totalDistributed || new Decimal(0),
      totalBurned: dailyStat?.totalBurned || new Decimal(0),
    };
  }

  /**
   * 交易统计
   */
  private async getTradingStats(date: Date) {
    const kline = await this.prisma.syncedDayKLine.findUnique({
      where: { klineDate: date },
    });

    return {
      tradingVolume: kline?.volume || new Decimal(0),
      tradingAmount: kline?.amount || new Decimal(0),
      tradeCount: kline?.tradeCount || 0,
    };
  }

  /**
   * 价格统计
   */
  private async getPriceStats(date: Date) {
    const kline = await this.prisma.syncedDayKLine.findUnique({
      where: { klineDate: date },
    });

    const defaultPrice = new Decimal(1);

    return {
      openPrice: kline?.open || defaultPrice,
      closePrice: kline?.close || defaultPrice,
      highPrice: kline?.high || defaultPrice,
      lowPrice: kline?.low || defaultPrice,
    };
  }
}
