import { Injectable, Logger } from '@nestjs/common';
import { Decimal } from '@prisma/client/runtime/library';
import { PrismaService } from '../prisma/prisma.service';
import {
  IRealtimeStatsRepository,
  RealtimeStatsData,
} from '../../../domain/repositories';

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

  constructor(private readonly prisma: PrismaService) {}

  async getOrCreateByDate(date: Date): Promise<RealtimeStatsData> {
    const statsDate = this.normalizeDate(date);

    const existing = await this.prisma.realtimeStats.findUnique({
      where: { statsDate },
    });

    if (existing) {
      return this.toDomain(existing);
    }

    const created = await this.prisma.realtimeStats.create({
      data: { statsDate },
    });

    return this.toDomain(created);
  }

  async findByDate(date: Date): Promise<RealtimeStatsData | null> {
    const statsDate = this.normalizeDate(date);

    const found = await this.prisma.realtimeStats.findUnique({
      where: { statsDate },
    });

    return found ? this.toDomain(found) : null;
  }

  async incrementPlanting(
    date: Date,
    treeCount: number,
    amount: Decimal,
  ): Promise<RealtimeStatsData> {
    const statsDate = this.normalizeDate(date);
    // [2026-01-07] 修复：防御性处理，确保 treeCount 不为 undefined
    const safeTreeCount = treeCount ?? 0;
    const safeAmount = amount ?? new Decimal(0);

    this.logger.debug(
      `Incrementing planting: date=${statsDate.toISOString()}, trees=${safeTreeCount}, amount=${safeAmount}`,
    );

    const result = await this.prisma.realtimeStats.upsert({
      where: { statsDate },
      create: {
        statsDate,
        dailyPlantingCount: safeTreeCount,
        dailyOrderCount: 1,
        dailyPlantingAmount: safeAmount,
      },
      update: {
        dailyPlantingCount: { increment: safeTreeCount },
        dailyOrderCount: { increment: 1 },
        dailyPlantingAmount: { increment: safeAmount },
      },
    });

    return this.toDomain(result);
  }

  async incrementOrder(date: Date): Promise<RealtimeStatsData> {
    const statsDate = this.normalizeDate(date);

    const result = await this.prisma.realtimeStats.upsert({
      where: { statsDate },
      create: {
        statsDate,
        dailyOrderCount: 1,
      },
      update: {
        dailyOrderCount: { increment: 1 },
      },
    });

    return this.toDomain(result);
  }

  async incrementNewUser(date: Date): Promise<RealtimeStatsData> {
    const statsDate = this.normalizeDate(date);
    this.logger.debug(`Incrementing new user: date=${statsDate.toISOString()}`);

    const result = await this.prisma.realtimeStats.upsert({
      where: { statsDate },
      create: {
        statsDate,
        dailyNewUserCount: 1,
      },
      update: {
        dailyNewUserCount: { increment: 1 },
      },
    });

    return this.toDomain(result);
  }

  async incrementProvinceAuth(date: Date): Promise<RealtimeStatsData> {
    const statsDate = this.normalizeDate(date);
    this.logger.debug(
      `Incrementing province auth: date=${statsDate.toISOString()}`,
    );

    const result = await this.prisma.realtimeStats.upsert({
      where: { statsDate },
      create: {
        statsDate,
        dailyProvinceAuthCount: 1,
      },
      update: {
        dailyProvinceAuthCount: { increment: 1 },
      },
    });

    return this.toDomain(result);
  }

  async incrementCityAuth(date: Date): Promise<RealtimeStatsData> {
    const statsDate = this.normalizeDate(date);
    this.logger.debug(`Incrementing city auth: date=${statsDate.toISOString()}`);

    const result = await this.prisma.realtimeStats.upsert({
      where: { statsDate },
      create: {
        statsDate,
        dailyCityAuthCount: 1,
      },
      update: {
        dailyCityAuthCount: { increment: 1 },
      },
    });

    return this.toDomain(result);
  }

  async findRecentDays(days: number): Promise<RealtimeStatsData[]> {
    const startDate = new Date();
    startDate.setDate(startDate.getDate() - days + 1);
    startDate.setHours(0, 0, 0, 0);

    const results = await this.prisma.realtimeStats.findMany({
      where: {
        statsDate: { gte: startDate },
      },
      orderBy: { statsDate: 'asc' },
    });

    return results.map((r) => this.toDomain(r));
  }

  async findByDateRange(
    startDate: Date,
    endDate: Date,
  ): Promise<RealtimeStatsData[]> {
    const results = await this.prisma.realtimeStats.findMany({
      where: {
        statsDate: {
          gte: this.normalizeDate(startDate),
          lte: this.normalizeDate(endDate),
        },
      },
      orderBy: { statsDate: 'asc' },
    });

    return results.map((r) => this.toDomain(r));
  }

  /**
   * 将日期标准化为当天0点
   */
  private normalizeDate(date: Date): Date {
    const normalized = new Date(date);
    normalized.setHours(0, 0, 0, 0);
    return normalized;
  }

  private toDomain(
    record: Awaited<ReturnType<typeof this.prisma.realtimeStats.findFirst>>,
  ): RealtimeStatsData {
    if (!record) {
      throw new Error('Record is null');
    }
    return {
      id: record.id,
      statsDate: record.statsDate,
      dailyPlantingCount: record.dailyPlantingCount,
      dailyOrderCount: record.dailyOrderCount,
      dailyPlantingAmount: record.dailyPlantingAmount,
      dailyNewUserCount: record.dailyNewUserCount,
      dailyProvinceAuthCount: record.dailyProvinceAuthCount,
      dailyCityAuthCount: record.dailyCityAuthCount,
      createdAt: record.createdAt,
      updatedAt: record.updatedAt,
    };
  }
}
