import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { IPoolInjectionBatchRepository } from '../../../domain/repositories/pool-injection-batch.repository.interface';
import { PoolInjectionBatch } from '../../../domain/aggregates/pool-injection-batch.aggregate';
import { BatchStatus } from '../../../domain/value-objects/batch-status.enum';
import { PoolInjectionBatchMapper } from '../mappers/pool-injection-batch.mapper';

@Injectable()
export class PoolInjectionBatchRepositoryImpl
  implements IPoolInjectionBatchRepository
{
  constructor(private readonly prisma: PrismaService) {}

  async save(batch: PoolInjectionBatch): Promise<void> {
    const data = PoolInjectionBatchMapper.toPersistence(batch);

    if (batch.id) {
      // 更新
      await this.prisma.poolInjectionBatch.update({
        where: { id: batch.id },
        data: {
          orderCount: data.orderCount,
          totalAmount: data.totalAmount,
          status: data.status,
          scheduledInjectionTime: data.scheduledInjectionTime,
          actualInjectionTime: data.actualInjectionTime,
          injectionTxHash: data.injectionTxHash,
        },
      });
    } else {
      // 创建
      const created = await this.prisma.poolInjectionBatch.create({
        data: {
          batchNo: data.batchNo,
          startDate: data.startDate,
          endDate: data.endDate,
          orderCount: data.orderCount,
          totalAmount: data.totalAmount,
          status: data.status,
          scheduledInjectionTime: data.scheduledInjectionTime,
          actualInjectionTime: data.actualInjectionTime,
          injectionTxHash: data.injectionTxHash,
        },
      });

      batch.setId(created.id);
    }
  }

  async findById(batchId: bigint): Promise<PoolInjectionBatch | null> {
    const batch = await this.prisma.poolInjectionBatch.findUnique({
      where: { id: batchId },
    });

    return batch ? PoolInjectionBatchMapper.toDomain(batch) : null;
  }

  async findByBatchNo(batchNo: string): Promise<PoolInjectionBatch | null> {
    const batch = await this.prisma.poolInjectionBatch.findUnique({
      where: { batchNo },
    });

    return batch ? PoolInjectionBatchMapper.toDomain(batch) : null;
  }

  async findByStatus(status: BatchStatus): Promise<PoolInjectionBatch[]> {
    const batches = await this.prisma.poolInjectionBatch.findMany({
      where: { status },
      orderBy: { startDate: 'asc' },
    });

    return batches.map(PoolInjectionBatchMapper.toDomain);
  }

  async findCurrentBatch(): Promise<PoolInjectionBatch | null> {
    const now = new Date();
    const batch = await this.prisma.poolInjectionBatch.findFirst({
      where: {
        status: BatchStatus.PENDING,
        startDate: { lte: now },
        endDate: { gte: now },
      },
      orderBy: { startDate: 'desc' },
    });

    return batch ? PoolInjectionBatchMapper.toDomain(batch) : null;
  }

  async findOrCreateCurrentBatch(): Promise<PoolInjectionBatch> {
    let batch = await this.findCurrentBatch();

    if (!batch) {
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      batch = PoolInjectionBatch.create(today);
      await this.save(batch);
    }

    return batch;
  }

  async findScheduledBatchesReadyForInjection(): Promise<PoolInjectionBatch[]> {
    const now = new Date();
    const batches = await this.prisma.poolInjectionBatch.findMany({
      where: {
        status: BatchStatus.SCHEDULED,
        scheduledInjectionTime: { lte: now },
      },
      orderBy: { scheduledInjectionTime: 'asc' },
    });

    return batches.map(PoolInjectionBatchMapper.toDomain);
  }
}
