import { Injectable, Logger } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import {
  PrePlantingOrder,
  PrePlantingOrderData,
} from '../../domain/aggregates/pre-planting-order.aggregate';
import { PrePlantingOrderStatus } from '../../domain/value-objects/pre-planting-order-status.enum';

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

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

    if (order.id) {
      await tx.prePlantingOrder.update({
        where: { id: order.id },
        data: {
          status: data.status,
          mergedToMergeId: data.mergedToMergeId || null,
          mergedAt: data.mergedAt || null,
          paidAt: data.paidAt || null,
        },
      });
    } else {
      const created = await tx.prePlantingOrder.create({
        data: {
          orderNo: data.orderNo,
          userId: data.userId,
          accountSequence: data.accountSequence,
          portionCount: data.portionCount,
          pricePerPortion: new Prisma.Decimal(data.pricePerPortion),
          totalAmount: new Prisma.Decimal(data.totalAmount),
          priceSupplement: data.priceSupplement ?? 0,
          provinceCode: data.provinceCode,
          cityCode: data.cityCode,
          status: data.status,
          createdAt: data.createdAt || new Date(),
          paidAt: data.paidAt || null,
        },
      });
      order.setId(created.id);
    }
  }

  async findByOrderNo(
    tx: Prisma.TransactionClient,
    orderNo: string,
  ): Promise<PrePlantingOrder | null> {
    const record = await tx.prePlantingOrder.findUnique({
      where: { orderNo },
    });
    if (!record) return null;
    return this.toDomain(record);
  }

  async findPaidOrdersByUserId(
    tx: Prisma.TransactionClient,
    userId: bigint,
  ): Promise<PrePlantingOrder[]> {
    const records = await tx.prePlantingOrder.findMany({
      where: { userId, status: PrePlantingOrderStatus.PAID },
      orderBy: { createdAt: 'asc' },
    });
    return records.map((r) => this.toDomain(r));
  }

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

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  private toDomain(record: any): PrePlantingOrder {
    const data: PrePlantingOrderData = {
      id: record.id,
      orderNo: record.orderNo,
      userId: record.userId,
      accountSequence: record.accountSequence,
      portionCount: record.portionCount,
      pricePerPortion: Number(record.pricePerPortion),
      totalAmount: Number(record.totalAmount),
      priceSupplement: record.priceSupplement ?? 0,
      provinceCode: record.provinceCode,
      cityCode: record.cityCode,
      status: record.status as PrePlantingOrderStatus,
      mergedToMergeId: record.mergedToMergeId,
      mergedAt: record.mergedAt,
      createdAt: record.createdAt,
      paidAt: record.paidAt,
    };
    return PrePlantingOrder.reconstitute(data);
  }
}
