import { Injectable, Logger } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import {
  PrePlantingPosition,
  PrePlantingPositionData,
} from '../../domain/aggregates/pre-planting-position.aggregate';

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

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

    if (position.id) {
      await tx.prePlantingPosition.update({
        where: { id: position.id },
        data: {
          totalPortions: data.totalPortions,
          availablePortions: data.availablePortions,
          mergedPortions: data.mergedPortions,
          totalTreesMerged: data.totalTreesMerged,
          provinceCode: data.provinceCode || null,
          provinceName: data.provinceName || null,
          cityCode: data.cityCode || null,
          cityName: data.cityName || null,
          firstPurchaseAt: data.firstPurchaseAt || null,
        },
      });
    } else {
      const created = await tx.prePlantingPosition.create({
        data: {
          userId: data.userId,
          accountSequence: data.accountSequence,
          totalPortions: data.totalPortions,
          availablePortions: data.availablePortions,
          mergedPortions: data.mergedPortions,
          totalTreesMerged: data.totalTreesMerged,
          provinceCode: data.provinceCode || null,
          provinceName: data.provinceName || null,
          cityCode: data.cityCode || null,
          cityName: data.cityName || null,
          firstPurchaseAt: data.firstPurchaseAt || null,
        },
      });
      position.setId(created.id);
    }
  }

  async getOrCreate(
    tx: Prisma.TransactionClient,
    userId: bigint,
    accountSequence: string,
  ): Promise<PrePlantingPosition> {
    const existing = await tx.prePlantingPosition.findUnique({
      where: { userId },
    });

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

    const position = PrePlantingPosition.create(userId, accountSequence);
    await this.save(tx, position);
    return position;
  }

  async findByUserId(
    tx: Prisma.TransactionClient,
    userId: bigint,
  ): Promise<PrePlantingPosition | null> {
    const record = await tx.prePlantingPosition.findUnique({
      where: { userId },
    });
    if (!record) return null;
    return this.toDomain(record);
  }

  async findByAccountSequence(
    tx: Prisma.TransactionClient,
    accountSequence: string,
  ): Promise<PrePlantingPosition | null> {
    const record = await tx.prePlantingPosition.findUnique({
      where: { accountSequence },
    });
    if (!record) return null;
    return this.toDomain(record);
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private toDomain(record: any): PrePlantingPosition {
    const data: PrePlantingPositionData = {
      id: record.id,
      userId: record.userId,
      accountSequence: record.accountSequence,
      totalPortions: record.totalPortions,
      availablePortions: record.availablePortions,
      mergedPortions: record.mergedPortions,
      totalTreesMerged: record.totalTreesMerged,
      provinceCode: record.provinceCode,
      provinceName: record.provinceName,
      cityCode: record.cityCode,
      cityName: record.cityName,
      firstPurchaseAt: record.firstPurchaseAt,
      createdAt: record.createdAt,
    };
    return PrePlantingPosition.reconstitute(data);
  }
}
