import { Injectable } from '@nestjs/common'
import { PrismaService } from '../prisma/prisma.service'
import {
  IBenefitAssessmentRecordRepository,
  BENEFIT_ASSESSMENT_RECORD_REPOSITORY,
} from '@/domain/repositories'
import { BenefitAssessmentRecord, BenefitAssessmentRecordProps } from '@/domain/aggregates'
import { AuthorizationId, UserId, RegionCode, Month } from '@/domain/value-objects'
import { RoleType, AssessmentResult, BenefitActionType } from '@/domain/enums'

@Injectable()
export class BenefitAssessmentRecordRepositoryImpl implements IBenefitAssessmentRecordRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(record: BenefitAssessmentRecord): Promise<void> {
    const data = record.toPersistence()
    await this.prisma.benefitAssessmentRecord.upsert({
      where: {
        authorizationId_assessmentMonth: {
          authorizationId: data.authorizationId,
          assessmentMonth: data.assessmentMonth,
        },
      },
      create: {
        id: data.id,
        authorizationId: data.authorizationId,
        userId: data.userId,
        accountSequence: data.accountSequence,
        roleType: data.roleType,
        regionCode: data.regionCode,
        regionName: data.regionName,
        assessmentMonth: data.assessmentMonth,
        monthIndex: data.monthIndex,
        monthlyTarget: data.monthlyTarget,
        cumulativeTarget: data.cumulativeTarget,
        treesCompleted: data.treesCompleted,
        treesRequired: data.treesRequired,
        benefitActionTaken: data.benefitActionTaken,
        previousBenefitStatus: data.previousBenefitStatus,
        newBenefitStatus: data.newBenefitStatus,
        newValidUntil: data.newValidUntil,
        result: data.result,
        remarks: data.remarks,
        assessedAt: data.assessedAt,
      },
      update: {
        treesCompleted: data.treesCompleted,
        treesRequired: data.treesRequired,
        benefitActionTaken: data.benefitActionTaken,
        previousBenefitStatus: data.previousBenefitStatus,
        newBenefitStatus: data.newBenefitStatus,
        newValidUntil: data.newValidUntil,
        result: data.result,
        remarks: data.remarks,
        assessedAt: data.assessedAt,
      },
    })
  }

  async saveAll(records: BenefitAssessmentRecord[]): Promise<void> {
    await this.prisma.$transaction(
      records.map((record) => {
        const data = record.toPersistence()
        return this.prisma.benefitAssessmentRecord.upsert({
          where: {
            authorizationId_assessmentMonth: {
              authorizationId: data.authorizationId,
              assessmentMonth: data.assessmentMonth,
            },
          },
          create: {
            id: data.id,
            authorizationId: data.authorizationId,
            userId: data.userId,
            accountSequence: data.accountSequence,
            roleType: data.roleType,
            regionCode: data.regionCode,
            regionName: data.regionName,
            assessmentMonth: data.assessmentMonth,
            monthIndex: data.monthIndex,
            monthlyTarget: data.monthlyTarget,
            cumulativeTarget: data.cumulativeTarget,
            treesCompleted: data.treesCompleted,
            treesRequired: data.treesRequired,
            benefitActionTaken: data.benefitActionTaken,
            previousBenefitStatus: data.previousBenefitStatus,
            newBenefitStatus: data.newBenefitStatus,
            newValidUntil: data.newValidUntil,
            result: data.result,
            remarks: data.remarks,
            assessedAt: data.assessedAt,
          },
          update: {
            treesCompleted: data.treesCompleted,
            treesRequired: data.treesRequired,
            benefitActionTaken: data.benefitActionTaken,
            previousBenefitStatus: data.previousBenefitStatus,
            newBenefitStatus: data.newBenefitStatus,
            newValidUntil: data.newValidUntil,
            result: data.result,
            remarks: data.remarks,
            assessedAt: data.assessedAt,
          },
        })
      }),
    )
  }

  async findById(id: string): Promise<BenefitAssessmentRecord | null> {
    const record = await this.prisma.benefitAssessmentRecord.findUnique({
      where: { id },
    })
    return record ? this.toDomain(record) : null
  }

  async findByAuthorizationAndMonth(
    authorizationId: AuthorizationId,
    month: Month,
  ): Promise<BenefitAssessmentRecord | null> {
    const record = await this.prisma.benefitAssessmentRecord.findFirst({
      where: {
        authorizationId: authorizationId.value,
        assessmentMonth: month.value,
      },
    })
    return record ? this.toDomain(record) : null
  }

  async findByUserAndMonth(userId: UserId, month: Month): Promise<BenefitAssessmentRecord[]> {
    const records = await this.prisma.benefitAssessmentRecord.findMany({
      where: {
        userId: userId.value,
        assessmentMonth: month.value,
      },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findByMonthAndRoleType(
    month: Month,
    roleType: RoleType,
  ): Promise<BenefitAssessmentRecord[]> {
    const records = await this.prisma.benefitAssessmentRecord.findMany({
      where: {
        assessmentMonth: month.value,
        roleType: roleType,
      },
      orderBy: { createdAt: 'desc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findByMonthAndRegion(
    month: Month,
    roleType: RoleType,
    regionCode: RegionCode,
  ): Promise<BenefitAssessmentRecord[]> {
    const records = await this.prisma.benefitAssessmentRecord.findMany({
      where: {
        assessmentMonth: month.value,
        roleType: roleType,
        regionCode: regionCode.value,
      },
      orderBy: { createdAt: 'desc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findByAuthorization(authorizationId: AuthorizationId): Promise<BenefitAssessmentRecord[]> {
    const records = await this.prisma.benefitAssessmentRecord.findMany({
      where: { authorizationId: authorizationId.value },
      orderBy: { monthIndex: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async delete(id: string): Promise<void> {
    await this.prisma.benefitAssessmentRecord.delete({
      where: { id },
    })
  }

  private toDomain(record: any): BenefitAssessmentRecord {
    const props: BenefitAssessmentRecordProps = {
      id: record.id,
      authorizationId: AuthorizationId.create(record.authorizationId),
      userId: UserId.create(record.userId, record.accountSequence),
      roleType: record.roleType as RoleType,
      regionCode: RegionCode.create(record.regionCode),
      regionName: record.regionName,
      assessmentMonth: Month.create(record.assessmentMonth),
      monthIndex: record.monthIndex,
      monthlyTarget: record.monthlyTarget,
      cumulativeTarget: record.cumulativeTarget,
      treesCompleted: record.treesCompleted,
      treesRequired: record.treesRequired,
      benefitActionTaken: record.benefitActionTaken as BenefitActionType,
      previousBenefitStatus: record.previousBenefitStatus,
      newBenefitStatus: record.newBenefitStatus,
      newValidUntil: record.newValidUntil,
      result: record.result as AssessmentResult,
      remarks: record.remarks,
      assessedAt: record.assessedAt,
      createdAt: record.createdAt,
    }
    return BenefitAssessmentRecord.fromPersistence(props)
  }
}

export { BENEFIT_ASSESSMENT_RECORD_REPOSITORY }
