import { Injectable, Logger } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import {
  PrePlantingMerge,
  PrePlantingMergeData,
} from '../../domain/aggregates/pre-planting-merge.aggregate';
import { PrePlantingContractStatus } from '../../domain/value-objects/pre-planting-contract-status.enum';

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

  async save(
    tx: Prisma.TransactionClient,
    merge: PrePlantingMerge,
  ): Promise<void> {
    const data = merge.toPersistence();

    if (merge.id) {
      await tx.prePlantingMerge.update({
        where: { id: merge.id },
        data: {
          provinceCode: data.provinceCode || null,
          cityCode: data.cityCode || null,
          contractStatus: data.contractStatus,
          contractSignedAt: data.contractSignedAt || null,
          miningEnabledAt: data.miningEnabledAt || null,
        },
      });
    } else {
      const created = await tx.prePlantingMerge.create({
        data: {
          mergeNo: data.mergeNo,
          userId: data.userId,
          accountSequence: data.accountSequence,
          sourceOrderNos: data.sourceOrderNos,
          treeCount: data.treeCount,
          provinceCode: data.provinceCode || null,
          cityCode: data.cityCode || null,
          contractStatus: data.contractStatus,
          contractSignedAt: data.contractSignedAt || null,
          miningEnabledAt: data.miningEnabledAt || null,
          mergedAt: data.mergedAt || new Date(),
        },
      });
      merge.setId(created.id);
    }
  }

  async findByMergeNo(
    tx: Prisma.TransactionClient,
    mergeNo: string,
  ): Promise<PrePlantingMerge | null> {
    const record = await tx.prePlantingMerge.findUnique({
      where: { mergeNo },
    });
    if (!record) return null;
    return this.toDomain(record);
  }

  async findByUserId(
    tx: Prisma.TransactionClient,
    userId: bigint,
  ): Promise<PrePlantingMerge[]> {
    const records = await tx.prePlantingMerge.findMany({
      where: { userId },
      orderBy: { mergedAt: 'desc' },
    });
    return records.map((r) => this.toDomain(r));
  }

  async findPendingByUserId(
    tx: Prisma.TransactionClient,
    userId: bigint,
  ): Promise<PrePlantingMerge[]> {
    const records = await tx.prePlantingMerge.findMany({
      where: {
        userId,
        contractStatus: PrePlantingContractStatus.PENDING,
      },
      orderBy: { mergedAt: 'desc' },
    });
    return records.map((r) => this.toDomain(r));
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private toDomain(record: any): PrePlantingMerge {
    const data: PrePlantingMergeData = {
      id: record.id,
      mergeNo: record.mergeNo,
      userId: record.userId,
      accountSequence: record.accountSequence,
      sourceOrderNos: record.sourceOrderNos as string[],
      treeCount: record.treeCount,
      provinceCode: record.provinceCode,
      cityCode: record.cityCode,
      contractStatus: record.contractStatus as PrePlantingContractStatus,
      contractSignedAt: record.contractSignedAt,
      miningEnabledAt: record.miningEnabledAt,
      mergedAt: record.mergedAt,
    };
    return PrePlantingMerge.reconstitute(data);
  }
}
