import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import {
  IDashboardTrendDataRepository,
  DashboardTrendDataItem,
} from '../../../domain/repositories';

@Injectable()
export class DashboardTrendDataRepository
  implements IDashboardTrendDataRepository
{
  constructor(private readonly prisma: PrismaService) {}

  async save(data: DashboardTrendDataItem): Promise<DashboardTrendDataItem> {
    const result = await this.prisma.dashboardTrendData.upsert({
      where: {
        trendDate: data.trendDate,
      },
      update: {
        plantingCount: data.plantingCount,
        orderCount: data.orderCount,
        newUserCount: data.newUserCount,
        activeUserCount: data.activeUserCount,
      },
      create: {
        trendDate: data.trendDate,
        plantingCount: data.plantingCount,
        orderCount: data.orderCount,
        newUserCount: data.newUserCount,
        activeUserCount: data.activeUserCount,
      },
    });

    return this.toDomain(result);
  }

  async saveMany(dataList: DashboardTrendDataItem[]): Promise<number> {
    let count = 0;
    for (const data of dataList) {
      await this.save(data);
      count++;
    }
    return count;
  }

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

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

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

    const found = await this.prisma.dashboardTrendData.findMany({
      where: {
        trendDate: {
          gte: startDate,
        },
      },
      orderBy: { trendDate: 'asc' },
    });
    return found.map((item) => this.toDomain(item));
  }

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

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

  private toDomain(
    record: Awaited<
      ReturnType<typeof this.prisma.dashboardTrendData.findFirst>
    >,
  ): DashboardTrendDataItem {
    if (!record) {
      throw new Error('Record is null');
    }
    return {
      id: record.id,
      trendDate: record.trendDate,
      plantingCount: record.plantingCount,
      orderCount: record.orderCount,
      newUserCount: record.newUserCount,
      activeUserCount: record.activeUserCount,
      createdAt: record.createdAt,
      updatedAt: record.updatedAt,
    };
  }
}
