import { Injectable } from '@nestjs/common'
import { PrismaService } from '../prisma/prisma.service'
import {
  IMonthlyAssessmentRepository,
  MONTHLY_ASSESSMENT_REPOSITORY,
} from '@/domain/repositories'
import { MonthlyAssessment, MonthlyAssessmentProps } from '@/domain/aggregates'
import {
  AssessmentId,
  AuthorizationId,
  UserId,
  AdminUserId,
  RegionCode,
  Month,
} from '@/domain/value-objects'
import { RoleType, AssessmentResult } from '@/domain/enums'

@Injectable()
export class MonthlyAssessmentRepositoryImpl implements IMonthlyAssessmentRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(assessment: MonthlyAssessment): Promise<void> {
    const data = assessment.toPersistence()
    await this.prisma.monthlyAssessment.upsert({
      where: { id: data.id },
      create: {
        id: data.id,
        authorizationId: data.authorizationId,
        userId: data.userId,
        accountSequence: data.accountSequence,
        roleType: data.roleType,
        regionCode: data.regionCode,
        assessmentMonth: data.assessmentMonth,
        monthIndex: data.monthIndex,
        monthlyTarget: data.monthlyTarget,
        cumulativeTarget: data.cumulativeTarget,
        monthlyCompleted: data.monthlyCompleted,
        cumulativeCompleted: data.cumulativeCompleted,
        completedAt: data.completedAt,
        localTeamCount: data.localTeamCount,
        totalTeamCount: data.totalTeamCount,
        localPercentage: data.localPercentage,
        localPercentagePass: data.localPercentagePass,
        exceedRatio: data.exceedRatio,
        result: data.result,
        rankingInRegion: data.rankingInRegion,
        isFirstPlace: data.isFirstPlace,
        isBypassed: data.isBypassed,
        bypassedBy: data.bypassedBy,
        bypassedAt: data.bypassedAt,
        assessedAt: data.assessedAt,
      },
      update: {
        monthlyCompleted: data.monthlyCompleted,
        cumulativeCompleted: data.cumulativeCompleted,
        completedAt: data.completedAt,
        localTeamCount: data.localTeamCount,
        totalTeamCount: data.totalTeamCount,
        localPercentage: data.localPercentage,
        localPercentagePass: data.localPercentagePass,
        exceedRatio: data.exceedRatio,
        result: data.result,
        rankingInRegion: data.rankingInRegion,
        isFirstPlace: data.isFirstPlace,
        isBypassed: data.isBypassed,
        bypassedBy: data.bypassedBy,
        bypassedAt: data.bypassedAt,
        assessedAt: data.assessedAt,
      },
    })
  }

  async saveAll(assessments: MonthlyAssessment[]): Promise<void> {
    await this.prisma.$transaction(
      assessments.map((assessment) => {
        const data = assessment.toPersistence()
        return this.prisma.monthlyAssessment.upsert({
          where: { id: data.id },
          create: {
            id: data.id,
            authorizationId: data.authorizationId,
            userId: data.userId,
            accountSequence: data.accountSequence,
            roleType: data.roleType,
            regionCode: data.regionCode,
            assessmentMonth: data.assessmentMonth,
            monthIndex: data.monthIndex,
            monthlyTarget: data.monthlyTarget,
            cumulativeTarget: data.cumulativeTarget,
            monthlyCompleted: data.monthlyCompleted,
            cumulativeCompleted: data.cumulativeCompleted,
            completedAt: data.completedAt,
            localTeamCount: data.localTeamCount,
            totalTeamCount: data.totalTeamCount,
            localPercentage: data.localPercentage,
            localPercentagePass: data.localPercentagePass,
            exceedRatio: data.exceedRatio,
            result: data.result,
            rankingInRegion: data.rankingInRegion,
            isFirstPlace: data.isFirstPlace,
            isBypassed: data.isBypassed,
            bypassedBy: data.bypassedBy,
            bypassedAt: data.bypassedAt,
            assessedAt: data.assessedAt,
          },
          update: {
            monthlyCompleted: data.monthlyCompleted,
            cumulativeCompleted: data.cumulativeCompleted,
            completedAt: data.completedAt,
            localTeamCount: data.localTeamCount,
            totalTeamCount: data.totalTeamCount,
            localPercentage: data.localPercentage,
            localPercentagePass: data.localPercentagePass,
            exceedRatio: data.exceedRatio,
            result: data.result,
            rankingInRegion: data.rankingInRegion,
            isFirstPlace: data.isFirstPlace,
            isBypassed: data.isBypassed,
            bypassedBy: data.bypassedBy,
            bypassedAt: data.bypassedAt,
            assessedAt: data.assessedAt,
          },
        })
      }),
    )
  }

  async findById(assessmentId: AssessmentId): Promise<MonthlyAssessment | null> {
    const record = await this.prisma.monthlyAssessment.findUnique({
      where: { id: assessmentId.value },
    })
    return record ? this.toDomain(record) : null
  }

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

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

  async findFirstByAuthorization(
    authorizationId: AuthorizationId,
  ): Promise<MonthlyAssessment | null> {
    const record = await this.prisma.monthlyAssessment.findFirst({
      where: { authorizationId: authorizationId.value },
      orderBy: { monthIndex: 'asc' },
    })
    return record ? this.toDomain(record) : null
  }

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

  async findRankingsByMonthAndRegion(
    month: Month,
    roleType: RoleType,
    regionCode: RegionCode,
  ): Promise<MonthlyAssessment[]> {
    const records = await this.prisma.monthlyAssessment.findMany({
      where: {
        assessmentMonth: month.value,
        roleType: roleType,
        regionCode: regionCode.value,
        // 过滤掉已撤销授权的考核记录
        authorization: {
          status: { not: 'REVOKED' },
        },
      },
      orderBy: [{ exceedRatio: 'desc' }, { completedAt: 'asc' }],
    })
    return records.map((record) => this.toDomain(record))
  }

  async findRankingsByMonthAndRoleType(
    month: Month,
    roleType: RoleType,
  ): Promise<MonthlyAssessment[]> {
    const records = await this.prisma.monthlyAssessment.findMany({
      where: {
        assessmentMonth: month.value,
        roleType: roleType,
        // 过滤掉已撤销授权的考核记录
        authorization: {
          status: { not: 'REVOKED' },
        },
      },
      orderBy: [{ exceedRatio: 'desc' }, { completedAt: 'asc' }],
    })
    return records.map((record) => this.toDomain(record))
  }

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

  async delete(assessmentId: AssessmentId): Promise<void> {
    await this.prisma.monthlyAssessment.delete({
      where: { id: assessmentId.value },
    })
  }

  private toDomain(record: any): MonthlyAssessment {
    const props: MonthlyAssessmentProps = {
      assessmentId: AssessmentId.create(record.id),
      authorizationId: AuthorizationId.create(record.authorizationId),
      userId: UserId.create(record.userId, record.accountSequence),
      roleType: record.roleType as RoleType,
      regionCode: RegionCode.create(record.regionCode),
      assessmentMonth: Month.create(record.assessmentMonth),
      monthIndex: record.monthIndex,
      monthlyTarget: record.monthlyTarget,
      cumulativeTarget: record.cumulativeTarget,
      monthlyCompleted: record.monthlyCompleted,
      cumulativeCompleted: record.cumulativeCompleted,
      completedAt: record.completedAt,
      localTeamCount: record.localTeamCount,
      totalTeamCount: record.totalTeamCount,
      localPercentage: Number(record.localPercentage),
      localPercentagePass: record.localPercentagePass,
      exceedRatio: Number(record.exceedRatio),
      result: record.result as AssessmentResult,
      rankingInRegion: record.rankingInRegion,
      isFirstPlace: record.isFirstPlace,
      isBypassed: record.isBypassed,
      bypassedBy: record.bypassedBy ? AdminUserId.create(record.bypassedBy, record.bypassedBy) : null,
      bypassedAt: record.bypassedAt,
      assessedAt: record.assessedAt,
      createdAt: record.createdAt,
      updatedAt: record.updatedAt,
    }
    return MonthlyAssessment.fromPersistence(props)
  }
}

export { MONTHLY_ASSESSMENT_REPOSITORY }
