import { Injectable } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
import {
  IDashboardStatsSnapshotRepository,
  DashboardStatsSnapshotData,
} from '../../../domain/repositories';

@Injectable()
export class DashboardStatsSnapshotRepository
  implements IDashboardStatsSnapshotRepository
{
  constructor(private readonly prisma: PrismaService) {}

  async save(
    snapshot: DashboardStatsSnapshotData,
  ): Promise<DashboardStatsSnapshotData> {
    const data = {
      snapshotDate: snapshot.snapshotDate,
      totalPlantingCount: snapshot.totalPlantingCount,
      totalPlantingChange: new Prisma.Decimal(snapshot.totalPlantingChange),
      activeUserCount: snapshot.activeUserCount,
      activeUserChange: new Prisma.Decimal(snapshot.activeUserChange),
      provinceCompanyCount: snapshot.provinceCompanyCount,
      provinceCompanyChange: new Prisma.Decimal(snapshot.provinceCompanyChange),
      cityCompanyCount: snapshot.cityCompanyCount,
      cityCompanyChange: new Prisma.Decimal(snapshot.cityCompanyChange),
      regionDistribution: snapshot.regionDistribution as Prisma.InputJsonValue,
    };

    const result = await this.prisma.dashboardStatsSnapshot.upsert({
      where: {
        snapshotDate: snapshot.snapshotDate,
      },
      update: data,
      create: data,
    });

    return this.toDomain(result);
  }

  async findById(id: bigint): Promise<DashboardStatsSnapshotData | null> {
    const found = await this.prisma.dashboardStatsSnapshot.findUnique({
      where: { id },
    });
    return found ? this.toDomain(found) : null;
  }

  async findByDate(date: Date): Promise<DashboardStatsSnapshotData | null> {
    const found = await this.prisma.dashboardStatsSnapshot.findUnique({
      where: {
        snapshotDate: date,
      },
    });
    return found ? this.toDomain(found) : null;
  }

  async findLatest(): Promise<DashboardStatsSnapshotData | null> {
    const found = await this.prisma.dashboardStatsSnapshot.findFirst({
      orderBy: { snapshotDate: 'desc' },
    });
    return found ? this.toDomain(found) : null;
  }

  async findByDateRange(
    startDate: Date,
    endDate: Date,
  ): Promise<DashboardStatsSnapshotData[]> {
    const found = await this.prisma.dashboardStatsSnapshot.findMany({
      where: {
        snapshotDate: {
          gte: startDate,
          lte: endDate,
        },
      },
      orderBy: { snapshotDate: 'desc' },
    });
    return found.map((item) => this.toDomain(item));
  }

  async deleteBeforeDate(date: Date): Promise<number> {
    const result = await this.prisma.dashboardStatsSnapshot.deleteMany({
      where: {
        snapshotDate: {
          lt: date,
        },
      },
    });
    return result.count;
  }

  private toDomain(
    record: Awaited<
      ReturnType<typeof this.prisma.dashboardStatsSnapshot.findFirst>
    >,
  ): DashboardStatsSnapshotData {
    if (!record) {
      throw new Error('Record is null');
    }
    return {
      id: record.id,
      snapshotDate: record.snapshotDate,
      totalPlantingCount: record.totalPlantingCount,
      totalPlantingChange: record.totalPlantingChange.toNumber(),
      activeUserCount: record.activeUserCount,
      activeUserChange: record.activeUserChange.toNumber(),
      provinceCompanyCount: record.provinceCompanyCount,
      provinceCompanyChange: record.provinceCompanyChange.toNumber(),
      cityCompanyCount: record.cityCompanyCount,
      cityCompanyChange: record.cityCompanyChange.toNumber(),
      regionDistribution: record.regionDistribution as Record<string, unknown>,
      createdAt: record.createdAt,
      updatedAt: record.updatedAt,
    };
  }
}
