import { Injectable } from '@nestjs/common'
import { PrismaService } from '../prisma/prisma.service'
import {
  IAuthorizationRoleRepository,
  AUTHORIZATION_ROLE_REPOSITORY,
} from '@/domain/repositories'
import { AuthorizationRole, AuthorizationRoleProps } from '@/domain/aggregates'
import {
  AuthorizationId,
  UserId,
  AdminUserId,
  RegionCode,
  AssessmentConfig,
} from '@/domain/value-objects'
import { RoleType, AuthorizationStatus, MonthlyTargetType } from '@/domain/enums'
import { RegionCodeResolver } from '@/domain/region-code-resolver'

@Injectable()
export class AuthorizationRoleRepositoryImpl implements IAuthorizationRoleRepository {
  constructor(private readonly prisma: PrismaService) {}

  // 软删除过滤条件 (大厂通用做法)
  private readonly notDeleted = { deletedAt: null }

  async save(authorization: AuthorizationRole): Promise<void> {
    const data = authorization.toPersistence()
    await this.prisma.authorizationRole.upsert({
      where: { id: data.id },
      create: {
        id: data.id,
        userId: data.userId,
        accountSequence: data.accountSequence,
        roleType: data.roleType,
        regionCode: data.regionCode,
        regionName: data.regionName,
        status: data.status,
        displayTitle: data.displayTitle,
        authorizedAt: data.authorizedAt,
        authorizedBy: data.authorizedBy,
        revokedAt: data.revokedAt,
        revokedBy: data.revokedBy,
        revokeReason: data.revokeReason,
        initialTargetTreeCount: data.initialTargetTreeCount,
        monthlyTargetType: data.monthlyTargetType,
        requireLocalPercentage: data.requireLocalPercentage,
        exemptFromPercentageCheck: data.exemptFromPercentageCheck,
        benefitActive: data.benefitActive,
        benefitActivatedAt: data.benefitActivatedAt,
        benefitDeactivatedAt: data.benefitDeactivatedAt,
        benefitValidUntil: data.benefitValidUntil,
        lastAssessmentMonth: data.lastAssessmentMonth,
        monthlyTreesAdded: data.monthlyTreesAdded,
        lastMonthTreesAdded: data.lastMonthTreesAdded,
        currentMonthIndex: data.currentMonthIndex,
        officePhotoUrls: data.officePhotoUrls,
        deletedAt: data.deletedAt,
      },
      update: {
        status: data.status,
        displayTitle: data.displayTitle,
        authorizedAt: data.authorizedAt,
        authorizedBy: data.authorizedBy,
        revokedAt: data.revokedAt,
        revokedBy: data.revokedBy,
        revokeReason: data.revokeReason,
        requireLocalPercentage: data.requireLocalPercentage,
        exemptFromPercentageCheck: data.exemptFromPercentageCheck,
        benefitActive: data.benefitActive,
        benefitActivatedAt: data.benefitActivatedAt,
        benefitDeactivatedAt: data.benefitDeactivatedAt,
        benefitValidUntil: data.benefitValidUntil,
        lastAssessmentMonth: data.lastAssessmentMonth,
        monthlyTreesAdded: data.monthlyTreesAdded,
        lastMonthTreesAdded: data.lastMonthTreesAdded,
        currentMonthIndex: data.currentMonthIndex,
        officePhotoUrls: data.officePhotoUrls,
        deletedAt: data.deletedAt,
      },
    })
  }

  async findById(authorizationId: AuthorizationId): Promise<AuthorizationRole | null> {
    const record = await this.prisma.authorizationRole.findFirst({
      where: { id: authorizationId.value, ...this.notDeleted },
    })
    return record ? this.toDomain(record) : null
  }

  async findByUserIdAndRoleType(
    userId: UserId,
    roleType: RoleType,
  ): Promise<AuthorizationRole | null> {
    const record = await this.prisma.authorizationRole.findFirst({
      where: {
        accountSequence: userId.accountSequence,
        roleType: roleType,
        ...this.notDeleted,
      },
    })
    return record ? this.toDomain(record) : null
  }

  async findByUserIdRoleTypeAndRegion(
    userId: UserId,
    roleType: RoleType,
    regionCode: RegionCode,
  ): Promise<AuthorizationRole | null> {
    const record = await this.prisma.authorizationRole.findFirst({
      where: {
        accountSequence: userId.accountSequence,
        roleType: roleType,
        regionCode: regionCode.value,
        ...this.notDeleted,
      },
    })
    return record ? this.toDomain(record) : null
  }

  async findByAccountSequenceAndRoleType(
    accountSequence: string,
    roleType: RoleType,
  ): Promise<AuthorizationRole | null> {
    const record = await this.prisma.authorizationRole.findFirst({
      where: {
        accountSequence: accountSequence,
        roleType: roleType,
        ...this.notDeleted,
      },
    })
    return record ? this.toDomain(record) : null
  }

  async findByUserId(userId: UserId): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: { accountSequence: userId.accountSequence, ...this.notDeleted },
      orderBy: { createdAt: 'desc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findByAccountSequence(accountSequence: string): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: { accountSequence: accountSequence, ...this.notDeleted },
      orderBy: { createdAt: 'desc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findActiveByRoleTypeAndRegion(
    roleType: RoleType,
    regionCode: RegionCode,
  ): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        roleType: roleType,
        regionCode: regionCode.value,
        status: AuthorizationStatus.AUTHORIZED,
        benefitActive: true,
        ...this.notDeleted,
      },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findAllActive(roleType?: RoleType): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        status: AuthorizationStatus.AUTHORIZED,
        benefitActive: true,
        ...(roleType && { roleType }),
        ...this.notDeleted,
      },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findPendingByUserId(userId: UserId): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        accountSequence: userId.accountSequence,
        status: AuthorizationStatus.PENDING,
        ...this.notDeleted,
      },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findByStatus(status: AuthorizationStatus): Promise<AuthorizationRole[]> {
    // 查询 REVOKED 状态时不过滤 deletedAt，因为撤销操作会同时设置 deletedAt
    const whereClause = status === AuthorizationStatus.REVOKED
      ? { status }
      : { status, ...this.notDeleted }
    const records = await this.prisma.authorizationRole.findMany({
      where: whereClause,
    })
    return records.map((record) => this.toDomain(record))
  }

  async delete(authorizationId: AuthorizationId): Promise<void> {
    await this.prisma.authorizationRole.delete({
      where: { id: authorizationId.value },
    })
  }

  async findActiveCommunityByAccountSequences(
    accountSequences: string[],
  ): Promise<AuthorizationRole[]> {
    if (accountSequences.length === 0) {
      return []
    }

    // 只要求已授权状态，不要求权益已激活
    // 这样未通过考核的社区也能被识别为上级社区
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        accountSequence: { in: accountSequences },
        roleType: RoleType.COMMUNITY,
        status: AuthorizationStatus.AUTHORIZED,
        ...this.notDeleted,
      },
      orderBy: { accountSequence: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findActiveProvinceByAccountSequencesAndRegion(
    accountSequences: string[],
    provinceCode: string,
  ): Promise<AuthorizationRole[]> {
    if (accountSequences.length === 0) {
      return []
    }

    const allProvinceForms = RegionCodeResolver.resolveProvince(provinceCode)
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        accountSequence: { in: accountSequences },
        roleType: RoleType.PROVINCE_COMPANY,
        regionCode: { in: allProvinceForms },
        status: AuthorizationStatus.AUTHORIZED,
        benefitActive: true,
        ...this.notDeleted,
      },
      orderBy: { accountSequence: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findActiveCityByAccountSequencesAndRegion(
    accountSequences: string[],
    cityCode: string,
  ): Promise<AuthorizationRole[]> {
    if (accountSequences.length === 0) {
      return []
    }

    const allCityForms = RegionCodeResolver.resolveCity(cityCode)
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        accountSequence: { in: accountSequences },
        roleType: RoleType.CITY_COMPANY,
        regionCode: { in: allCityForms },
        status: AuthorizationStatus.AUTHORIZED,
        benefitActive: true,
        ...this.notDeleted,
      },
      orderBy: { accountSequence: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findCommunityByAccountSequences(
    accountSequences: string[],
  ): Promise<AuthorizationRole[]> {
    if (accountSequences.length === 0) {
      return []
    }

    const records = await this.prisma.authorizationRole.findMany({
      where: {
        accountSequence: { in: accountSequences },
        roleType: RoleType.COMMUNITY,
        status: AuthorizationStatus.AUTHORIZED,
        ...this.notDeleted,
        // 注意：不过滤 benefitActive，用于计算社区权益分配
      },
      orderBy: { accountSequence: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findAuthProvinceByAccountSequencesAndRegion(
    accountSequences: string[],
    provinceCode: string,
  ): Promise<AuthorizationRole[]> {
    if (accountSequences.length === 0) {
      return []
    }

    const allProvinceForms = RegionCodeResolver.resolveProvince(provinceCode)
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        accountSequence: { in: accountSequences },
        roleType: RoleType.AUTH_PROVINCE_COMPANY,
        regionCode: { in: allProvinceForms },
        status: AuthorizationStatus.AUTHORIZED,
        ...this.notDeleted,
        // 注意：不过滤 benefitActive，用于计算省团队权益分配
      },
      orderBy: { accountSequence: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findAuthCityByAccountSequencesAndRegion(
    accountSequences: string[],
    cityCode: string,
  ): Promise<AuthorizationRole[]> {
    if (accountSequences.length === 0) {
      return []
    }

    const allCityForms = RegionCodeResolver.resolveCity(cityCode)
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        accountSequence: { in: accountSequences },
        roleType: RoleType.AUTH_CITY_COMPANY,
        regionCode: { in: allCityForms },
        status: AuthorizationStatus.AUTHORIZED,
        ...this.notDeleted,
        // 注意：不过滤 benefitActive，用于计算市团队权益分配
      },
      orderBy: { accountSequence: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findAuthProvinceByAccountSequences(
    accountSequences: string[],
  ): Promise<AuthorizationRole[]> {
    if (accountSequences.length === 0) {
      return []
    }

    const records = await this.prisma.authorizationRole.findMany({
      where: {
        accountSequence: { in: accountSequences },
        roleType: RoleType.AUTH_PROVINCE_COMPANY,
        status: AuthorizationStatus.AUTHORIZED,
        ...this.notDeleted,
        // 注意：不过滤 benefitActive，用于计算省团队权益分配
        // 注意：不过滤 regionCode，省团队收益不要求省份匹配
      },
      orderBy: { accountSequence: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findAuthCityByAccountSequences(
    accountSequences: string[],
  ): Promise<AuthorizationRole[]> {
    if (accountSequences.length === 0) {
      return []
    }

    const records = await this.prisma.authorizationRole.findMany({
      where: {
        accountSequence: { in: accountSequences },
        roleType: RoleType.AUTH_CITY_COMPANY,
        status: AuthorizationStatus.AUTHORIZED,
        ...this.notDeleted,
        // 注意：不过滤 benefitActive，用于计算市团队权益分配
        // 注意：不过滤 regionCode，市团队收益不要求城市匹配
      },
      orderBy: { accountSequence: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findProvinceCompanyByRegion(provinceCode: string): Promise<AuthorizationRole | null> {
    // [2026-03-01] 使用 RegionCodeResolver 多形式匹配
    // 传入的可能是数字代码("440000")或中文名("广东"/"广东省")，
    // 数据库 regionCode 存储格式不统一，需要同时匹配所有可能形式。
    const allForms = RegionCodeResolver.resolveProvince(provinceCode)
    const record = await this.prisma.authorizationRole.findFirst({
      where: {
        roleType: RoleType.PROVINCE_COMPANY,
        regionCode: { in: allForms },
        status: AuthorizationStatus.AUTHORIZED,
        ...this.notDeleted,
      },
    })
    return record ? this.toDomain(record) : null
  }

  async findCityCompanyByRegion(cityCode: string): Promise<AuthorizationRole | null> {
    // [2026-03-01] 使用 RegionCodeResolver 多形式匹配（与省级同理）
    const allForms = RegionCodeResolver.resolveCity(cityCode)
    const record = await this.prisma.authorizationRole.findFirst({
      where: {
        roleType: RoleType.CITY_COMPANY,
        regionCode: { in: allForms },
        status: AuthorizationStatus.AUTHORIZED,
        ...this.notDeleted,
      },
    })
    return record ? this.toDomain(record) : null
  }

  async findExpiredActiveByRoleType(
    roleType: RoleType,
    checkDate: Date,
    limit: number,
  ): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        roleType: roleType,
        status: AuthorizationStatus.AUTHORIZED,
        benefitActive: true,
        benefitValidUntil: {
          lt: checkDate,
        },
        ...this.notDeleted,
      },
      take: limit,
      orderBy: { benefitValidUntil: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findCommunityByName(communityName: string): Promise<AuthorizationRole | null> {
    const record = await this.prisma.authorizationRole.findFirst({
      where: {
        roleType: RoleType.COMMUNITY,
        regionCode: communityName,
        ...this.notDeleted,
      },
    })
    return record ? this.toDomain(record) : null
  }

  // ============ 审计查询方法 (包含已软删除的记录) ============

  async findAllByUserIdIncludeDeleted(userId: UserId): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: { accountSequence: userId.accountSequence },
      orderBy: { createdAt: 'desc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findAllByAccountSequenceIncludeDeleted(accountSequence: string): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: { accountSequence: accountSequence },
      orderBy: { createdAt: 'desc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findByIdIncludeDeleted(authorizationId: AuthorizationId): Promise<AuthorizationRole | null> {
    const record = await this.prisma.authorizationRole.findUnique({
      where: { id: authorizationId.value },
    })
    return record ? this.toDomain(record) : null
  }

  // ============ 自动升级检查方法 ============

  async findAllActiveAuthProvinceCompanies(): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        roleType: RoleType.AUTH_PROVINCE_COMPANY,
        status: AuthorizationStatus.AUTHORIZED,
        benefitActive: true,
        ...this.notDeleted,
      },
      orderBy: { createdAt: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  async findAllActiveAuthCityCompanies(): Promise<AuthorizationRole[]> {
    const records = await this.prisma.authorizationRole.findMany({
      where: {
        roleType: RoleType.AUTH_CITY_COMPANY,
        status: AuthorizationStatus.AUTHORIZED,
        benefitActive: true,
        ...this.notDeleted,
      },
      orderBy: { createdAt: 'asc' },
    })
    return records.map((record) => this.toDomain(record))
  }

  private toDomain(record: any): AuthorizationRole {
    const props: AuthorizationRoleProps = {
      authorizationId: AuthorizationId.create(record.id),
      userId: UserId.create(record.userId, record.accountSequence),
      roleType: record.roleType as RoleType,
      regionCode: RegionCode.create(record.regionCode),
      regionName: record.regionName,
      status: record.status as AuthorizationStatus,
      displayTitle: record.displayTitle,
      authorizedAt: record.authorizedAt,
      authorizedBy: record.authorizedBy ? AdminUserId.create(record.authorizedBy, record.authorizedBy) : null,
      revokedAt: record.revokedAt,
      revokedBy: record.revokedBy ? AdminUserId.create(record.revokedBy, record.revokedBy) : null,
      revokeReason: record.revokeReason,
      assessmentConfig: new AssessmentConfig(
        record.initialTargetTreeCount,
        record.monthlyTargetType as MonthlyTargetType,
      ),
      requireLocalPercentage: Number(record.requireLocalPercentage),
      exemptFromPercentageCheck: record.exemptFromPercentageCheck,
      benefitActive: record.benefitActive,
      benefitActivatedAt: record.benefitActivatedAt,
      benefitDeactivatedAt: record.benefitDeactivatedAt,
      benefitValidUntil: record.benefitValidUntil,
      lastAssessmentMonth: record.lastAssessmentMonth,
      monthlyTreesAdded: record.monthlyTreesAdded ?? 0,
      lastMonthTreesAdded: record.lastMonthTreesAdded ?? 0,
      currentMonthIndex: record.currentMonthIndex,
      officePhotoUrls: record.officePhotoUrls ?? [],
      deletedAt: record.deletedAt,
      createdAt: record.createdAt,
      updatedAt: record.updatedAt,
    }
    return AuthorizationRole.fromPersistence(props)
  }
}

export { AUTHORIZATION_ROLE_REPOSITORY }
