import { Injectable, Inject, Logger } from '@nestjs/common'
import { Cron, CronExpression } from '@nestjs/schedule'
import { AuthorizationRole } from '@/domain/aggregates'
import { Month, RegionCode } from '@/domain/value-objects'
import { RoleType, AssessmentResult } from '@/domain/enums'
import {
  IAuthorizationRoleRepository,
  AUTHORIZATION_ROLE_REPOSITORY,
  IMonthlyAssessmentRepository,
  MONTHLY_ASSESSMENT_REPOSITORY,
} from '@/domain/repositories'
import { AssessmentCalculatorService, ITeamStatisticsRepository } from '@/domain/services'
import { EventPublisherService } from '@/infrastructure/kafka'
import { TEAM_STATISTICS_REPOSITORY, AuthorizationApplicationService } from '@/application/services'

@Injectable()
export class MonthlyAssessmentScheduler {
  private readonly logger = new Logger(MonthlyAssessmentScheduler.name)
  private readonly calculatorService = new AssessmentCalculatorService()

  constructor(
    @Inject(AUTHORIZATION_ROLE_REPOSITORY)
    private readonly authorizationRepository: IAuthorizationRoleRepository,
    @Inject(MONTHLY_ASSESSMENT_REPOSITORY)
    private readonly assessmentRepository: IMonthlyAssessmentRepository,
    @Inject(TEAM_STATISTICS_REPOSITORY)
    private readonly statsRepository: ITeamStatisticsRepository,
    private readonly eventPublisher: EventPublisherService,
    private readonly authorizationAppService: AuthorizationApplicationService,
  ) {}

  /**
   * 每月1号凌晨2点执行月度考核
   */
  @Cron('0 2 1 * *')
  async executeMonthlyAssessment(): Promise<void> {
    this.logger.log('开始执行月度考核...')

    const previousMonth = Month.current().previous()

    try {
      // 1. 获取所有激活的授权
      const activeAuths = await this.authorizationRepository.findAllActive()

      // 2. 按角色类型和区域分组处理
      const groupedByRoleAndRegion = this.groupByRoleAndRegion(activeAuths)

      for (const [key, auths] of groupedByRoleAndRegion) {
        const [roleTypeStr, regionCodeStr] = key.split('|')
        const roleType = roleTypeStr as RoleType

        // 跳过正式省市公司（无月度考核）
        if (roleType === RoleType.PROVINCE_COMPANY || roleType === RoleType.CITY_COMPANY) {
          continue
        }

        // 执行考核并排名
        const assessments = await this.calculatorService.assessAndRankRegion(
          roleType,
          RegionCode.create(regionCodeStr),
          previousMonth,
          this.authorizationRepository,
          this.statsRepository,
          this.assessmentRepository,
        )

        // 保存考核结果
        await this.assessmentRepository.saveAll(assessments)

        // 处理不达标的授权
        for (const assessment of assessments) {
          if (assessment.result === AssessmentResult.FAIL) {
            const auth = auths.find((a) =>
              a.authorizationId.equals(assessment.authorizationId),
            )

            if (auth) {
              // 权益失效
              auth.deactivateBenefit('月度考核不达标')
              await this.authorizationRepository.save(auth)

              await this.eventPublisher.publishAll(auth.domainEvents)
              auth.clearDomainEvents()
            }
          } else if (assessment.isPassed()) {
            // 达标，递增月份索引
            const auth = auths.find((a) =>
              a.authorizationId.equals(assessment.authorizationId),
            )

            if (auth) {
              auth.incrementMonthIndex()
              await this.authorizationRepository.save(auth)
            }
          }

          await this.eventPublisher.publishAll(assessment.domainEvents)
          assessment.clearDomainEvents()
        }
      }

      this.logger.log('月度考核执行完成')
    } catch (error) {
      this.logger.error('月度考核执行失败', error)
      throw error
    }
  }

  /**
   * 每10分钟更新火柴人排名数据
   */
  @Cron('*/10 * * * *')
  async updateStickmanRankings(): Promise<void> {
    this.logger.log('开始更新火柴人排名数据...')

    try {
      const currentMonth = Month.current()

      // 获取所有激活的授权省/市公司
      const activeAuths = await this.authorizationRepository.findAllActive()

      const provinceAuths = activeAuths.filter(
        (a) => a.roleType === RoleType.AUTH_PROVINCE_COMPANY,
      )
      const cityAuths = activeAuths.filter(
        (a) => a.roleType === RoleType.AUTH_CITY_COMPANY,
      )

      // 按区域分组并更新排名
      const provinceRegions = new Set(provinceAuths.map((a) => a.regionCode.value))
      const cityRegions = new Set(cityAuths.map((a) => a.regionCode.value))

      for (const regionCode of provinceRegions) {
        await this.updateRegionRankings(
          RoleType.AUTH_PROVINCE_COMPANY,
          regionCode,
          currentMonth,
        )
      }

      for (const regionCode of cityRegions) {
        await this.updateRegionRankings(
          RoleType.AUTH_CITY_COMPANY,
          regionCode,
          currentMonth,
        )
      }

      this.logger.log('火柴人排名数据更新完成')
    } catch (error) {
      this.logger.error('火柴人排名数据更新失败', error)
    }
  }

  private async updateRegionRankings(
    roleType: RoleType,
    regionCode: string,
    currentMonth: Month,
  ): Promise<void> {
    const assessments = await this.calculatorService.assessAndRankRegion(
      roleType,
      RegionCode.create(regionCode),
      currentMonth,
      this.authorizationRepository,
      this.statsRepository,
      this.assessmentRepository,
    )

    await this.assessmentRepository.saveAll(assessments)
  }

  private groupByRoleAndRegion(
    authorizations: AuthorizationRole[],
  ): Map<string, AuthorizationRole[]> {
    const map = new Map<string, AuthorizationRole[]>()

    for (const auth of authorizations) {
      const key = `${auth.roleType}|${auth.regionCode.value}`
      const list = map.get(key) || []
      list.push(auth)
      map.set(key, list)
    }

    return map
  }

  /**
   * 每天凌晨3点检查并处理过期的社区权益
   *
   * 业务规则：
   * - 检查所有 benefitValidUntil < 当前时间 且 benefitActive=true 的社区
   * - 如果当月新增树数 >= 10，续期
   * - 如果不达标，级联停用该社区及其所有上级社区
   */
  @Cron('0 3 * * *')
  async processExpiredCommunityBenefits(): Promise<void> {
    this.logger.log('[processExpiredCommunityBenefits] 开始检查社区权益过期情况...')

    try {
      const result = await this.authorizationAppService.processExpiredCommunityBenefits(100)

      this.logger.log(
        `[processExpiredCommunityBenefits] 处理完成: ` +
        `已处理=${result.processedCount}, 已续期=${result.renewedCount}, 已停用=${result.deactivatedCount}`,
      )
    } catch (error) {
      this.logger.error('[processExpiredCommunityBenefits] 社区权益过期检查失败', error)
    }
  }

  /**
   * 每月1号凌晨0点存档并重置所有社区的月度新增树数
   *
   * 业务规则：
   * - 将当月业绩存档到 lastMonthTreesAdded（用于月度考核）
   * - 重置 monthlyTreesAdded 为0（开始新月累计）
   *
   * 注意：考核时会根据 benefitValidUntil 判断使用哪个月的数据
   * - 有效期在上月末 → 用 lastMonthTreesAdded
   * - 有效期在当月末 → 用 monthlyTreesAdded
   */
  @Cron('0 0 1 * *')
  async archiveAndResetMonthlyTreeCounts(): Promise<void> {
    this.logger.log('[archiveAndResetMonthlyTreeCounts] 开始存档并重置月度新增树数...')

    try {
      // 获取所有激活的社区
      const activeCommunities = await this.authorizationRepository.findAllActive(RoleType.COMMUNITY)

      let archivedCount = 0
      for (const community of activeCommunities) {
        if (community.benefitActive) {
          // 存档当月数据到 lastMonthTreesAdded，然后重置 monthlyTreesAdded
          community.archiveAndResetMonthlyTrees()
          await this.authorizationRepository.save(community)
          archivedCount++

          this.logger.debug(
            `[archiveAndResetMonthlyTreeCounts] 社区 ${community.userId.accountSequence}: ` +
            `存档=${community.lastMonthTreesAdded}, 当月已重置=0`,
          )
        }
      }

      this.logger.log(`[archiveAndResetMonthlyTreeCounts] 存档完成: 已处理 ${archivedCount} 个社区`)

      // 同时处理市团队授权
      await this.archiveAndResetAuthCityMonthlyTreeCounts()

      // 同时处理省团队授权
      await this.archiveAndResetAuthProvinceMonthlyTreeCounts()

      // 同时处理正式市公司
      await this.archiveAndResetCityCompanyMonthlyTreeCounts()

      // 同时处理正式省公司
      await this.archiveAndResetProvinceCompanyMonthlyTreeCounts()
    } catch (error) {
      this.logger.error('[archiveAndResetMonthlyTreeCounts] 月度树数存档失败', error)
    }
  }

  /**
   * 存档并重置所有市团队授权的月度新增树数
   *
   * 业务规则：
   * - 将当月业绩存档到 lastMonthTreesAdded（用于月度考核）
   * - 重置 monthlyTreesAdded 为0（开始新月累计）
   */
  private async archiveAndResetAuthCityMonthlyTreeCounts(): Promise<void> {
    this.logger.log('[archiveAndResetAuthCityMonthlyTreeCounts] 开始存档市团队月度新增树数...')

    try {
      // 获取所有激活的市团队授权
      const activeAuthCities = await this.authorizationRepository.findAllActive(RoleType.AUTH_CITY_COMPANY)

      let archivedCount = 0
      for (const authCity of activeAuthCities) {
        if (authCity.benefitActive) {
          // 存档当月数据到 lastMonthTreesAdded，然后重置 monthlyTreesAdded
          authCity.archiveAndResetMonthlyTrees()
          await this.authorizationRepository.save(authCity)
          archivedCount++

          this.logger.debug(
            `[archiveAndResetAuthCityMonthlyTreeCounts] 市团队授权 ${authCity.userId.accountSequence}: ` +
            `存档=${authCity.lastMonthTreesAdded}, 当月已重置=0`,
          )
        }
      }

      this.logger.log(`[archiveAndResetAuthCityMonthlyTreeCounts] 存档完成: 已处理 ${archivedCount} 个市团队授权`)
    } catch (error) {
      this.logger.error('[archiveAndResetAuthCityMonthlyTreeCounts] 市团队月度树数存档失败', error)
    }
  }

  /**
   * 存档并重置所有省团队授权的月度新增树数
   *
   * 业务规则：
   * - 将当月业绩存档到 lastMonthTreesAdded（用于月度考核）
   * - 重置 monthlyTreesAdded 为0（开始新月累计）
   */
  private async archiveAndResetAuthProvinceMonthlyTreeCounts(): Promise<void> {
    this.logger.log('[archiveAndResetAuthProvinceMonthlyTreeCounts] 开始存档省团队月度新增树数...')

    try {
      // 获取所有激活的省团队授权
      const activeAuthProvinces = await this.authorizationRepository.findAllActive(RoleType.AUTH_PROVINCE_COMPANY)

      let archivedCount = 0
      for (const authProvince of activeAuthProvinces) {
        if (authProvince.benefitActive) {
          // 存档当月数据到 lastMonthTreesAdded，然后重置 monthlyTreesAdded
          authProvince.archiveAndResetMonthlyTrees()
          await this.authorizationRepository.save(authProvince)
          archivedCount++

          this.logger.debug(
            `[archiveAndResetAuthProvinceMonthlyTreeCounts] 省团队授权 ${authProvince.userId.accountSequence}: ` +
            `存档=${authProvince.lastMonthTreesAdded}, 当月已重置=0`,
          )
        }
      }

      this.logger.log(`[archiveAndResetAuthProvinceMonthlyTreeCounts] 存档完成: 已处理 ${archivedCount} 个省团队授权`)
    } catch (error) {
      this.logger.error('[archiveAndResetAuthProvinceMonthlyTreeCounts] 省团队月度树数存档失败', error)
    }
  }

  /**
   * 每天凌晨4点检查并处理过期的市团队授权权益
   *
   * 业务规则：
   * - 检查所有 benefitValidUntil < 当前时间 且 benefitActive=true 的市团队授权
   * - 如果当月新增树数 >= 100，续期
   * - 如果不达标，级联停用该市团队授权及其所有上级市团队授权
   */
  @Cron('0 4 * * *')
  async processExpiredAuthCityBenefits(): Promise<void> {
    this.logger.log('[processExpiredAuthCityBenefits] 开始检查市团队授权权益过期情况...')

    try {
      const result = await this.authorizationAppService.processExpiredAuthCityBenefits(100)

      this.logger.log(
        `[processExpiredAuthCityBenefits] 处理完成: ` +
        `已处理=${result.processedCount}, 已续期=${result.renewedCount}, 已停用=${result.deactivatedCount}`,
      )
    } catch (error) {
      this.logger.error('[processExpiredAuthCityBenefits] 市团队授权权益过期检查失败', error)
    }
  }

  /**
   * 每天凌晨5点检查并处理过期的省团队授权权益
   *
   * 业务规则：
   * - 检查所有 benefitValidUntil < 当前时间 且 benefitActive=true 的省团队授权
   * - 如果当月新增树数 >= 500，续期
   * - 如果不达标，级联停用该省团队授权及其所有上级省团队授权
   */
  @Cron('0 5 * * *')
  async processExpiredAuthProvinceBenefits(): Promise<void> {
    this.logger.log('[processExpiredAuthProvinceBenefits] 开始检查省团队授权权益过期情况...')

    try {
      const result = await this.authorizationAppService.processExpiredAuthProvinceBenefits(100)

      this.logger.log(
        `[processExpiredAuthProvinceBenefits] 处理完成: ` +
        `已处理=${result.processedCount}, 已续期=${result.renewedCount}, 已停用=${result.deactivatedCount}`,
      )
    } catch (error) {
      this.logger.error('[processExpiredAuthProvinceBenefits] 省团队授权权益过期检查失败', error)
    }
  }

  /**
   * 每天23:59检查是否是当月最后一天，如果是则执行正式市公司(CITY_COMPANY)月度考核
   *
   * 业务规则：
   * - 检查所有 benefitValidUntil < 当前时间 且 benefitActive=true 的正式市公司
   * - 使用阶梯目标（第1月30，第2月60，...，第9月2350）
   * - 如果当月新增树数达标，续期并递增月份索引
   * - 如果不达标，停用权益并重置月份索引到1
   */
  @Cron('59 23 * * *')
  async processExpiredCityCompanyBenefits(): Promise<void> {
    // 判断是否是当月最后一天
    const now = new Date()
    const tomorrow = new Date(now)
    tomorrow.setDate(tomorrow.getDate() + 1)

    // 如果明天是1号，说明今天是当月最后一天
    if (tomorrow.getDate() !== 1) {
      return
    }

    this.logger.log('[processExpiredCityCompanyBenefits] 今天是月末，开始检查正式市公司权益过期情况...')

    try {
      const result = await this.authorizationAppService.processExpiredCityCompanyBenefits(100)

      this.logger.log(
        `[processExpiredCityCompanyBenefits] 处理完成: ` +
        `已处理=${result.processedCount}, 已续期=${result.renewedCount}, 已停用=${result.deactivatedCount}`,
      )
    } catch (error) {
      this.logger.error('[processExpiredCityCompanyBenefits] 正式市公司权益过期检查失败', error)
    }
  }

  /**
   * 存档并重置所有正式市公司的月度新增树数
   *
   * 业务规则：
   * - 将当月业绩存档到 lastMonthTreesAdded（用于月度考核）
   * - 重置 monthlyTreesAdded 为0（开始新月累计）
   */
  private async archiveAndResetCityCompanyMonthlyTreeCounts(): Promise<void> {
    this.logger.log('[archiveAndResetCityCompanyMonthlyTreeCounts] 开始存档正式市公司月度新增树数...')

    try {
      // 获取所有激活的正式市公司
      const activeCityCompanies = await this.authorizationRepository.findAllActive(RoleType.CITY_COMPANY)

      let archivedCount = 0
      for (const cityCompany of activeCityCompanies) {
        if (cityCompany.benefitActive) {
          // 存档当月数据到 lastMonthTreesAdded，然后重置 monthlyTreesAdded
          cityCompany.archiveAndResetMonthlyTrees()
          await this.authorizationRepository.save(cityCompany)
          archivedCount++

          this.logger.debug(
            `[archiveAndResetCityCompanyMonthlyTreeCounts] 正式市公司 ${cityCompany.userId.accountSequence}: ` +
            `存档=${cityCompany.lastMonthTreesAdded}, 当月已重置=0`,
          )
        }
      }

      this.logger.log(`[archiveAndResetCityCompanyMonthlyTreeCounts] 存档完成: 已处理 ${archivedCount} 个正式市公司`)
    } catch (error) {
      this.logger.error('[archiveAndResetCityCompanyMonthlyTreeCounts] 正式市公司月度树数存档失败', error)
    }
  }

  /**
   * 每天23:59检查是否是当月最后一天，如果是则执行正式省公司(PROVINCE_COMPANY)月度考核
   *
   * 业务规则：
   * - 检查所有 benefitValidUntil < 当前时间 且 benefitActive=true 的正式省公司
   * - 使用阶梯目标（第1月150，第2月300，...，第9月11750）
   * - 如果当月新增树数达标，续期并递增月份索引
   * - 如果不达标，停用权益并重置月份索引到1
   */
  @Cron('59 23 * * *')
  async processExpiredProvinceCompanyBenefits(): Promise<void> {
    // 判断是否是当月最后一天
    const now = new Date()
    const tomorrow = new Date(now)
    tomorrow.setDate(tomorrow.getDate() + 1)

    // 如果明天是1号，说明今天是当月最后一天
    if (tomorrow.getDate() !== 1) {
      return
    }

    this.logger.log('[processExpiredProvinceCompanyBenefits] 今天是月末，开始检查正式省公司权益过期情况...')

    try {
      const result = await this.authorizationAppService.processExpiredProvinceCompanyBenefits(100)

      this.logger.log(
        `[processExpiredProvinceCompanyBenefits] 处理完成: ` +
        `已处理=${result.processedCount}, 已续期=${result.renewedCount}, 已停用=${result.deactivatedCount}`,
      )
    } catch (error) {
      this.logger.error('[processExpiredProvinceCompanyBenefits] 正式省公司权益过期检查失败', error)
    }
  }

  /**
   * 存档并重置所有正式省公司的月度新增树数
   *
   * 业务规则：
   * - 将当月业绩存档到 lastMonthTreesAdded（用于月度考核）
   * - 重置 monthlyTreesAdded 为0（开始新月累计）
   */
  private async archiveAndResetProvinceCompanyMonthlyTreeCounts(): Promise<void> {
    this.logger.log('[archiveAndResetProvinceCompanyMonthlyTreeCounts] 开始存档正式省公司月度新增树数...')

    try {
      // 获取所有激活的正式省公司
      const activeProvinceCompanies = await this.authorizationRepository.findAllActive(RoleType.PROVINCE_COMPANY)

      let archivedCount = 0
      for (const provinceCompany of activeProvinceCompanies) {
        if (provinceCompany.benefitActive) {
          // 存档当月数据到 lastMonthTreesAdded，然后重置 monthlyTreesAdded
          provinceCompany.archiveAndResetMonthlyTrees()
          await this.authorizationRepository.save(provinceCompany)
          archivedCount++

          this.logger.debug(
            `[archiveAndResetProvinceCompanyMonthlyTreeCounts] 正式省公司 ${provinceCompany.userId.accountSequence}: ` +
            `存档=${provinceCompany.lastMonthTreesAdded}, 当月已重置=0`,
          )
        }
      }

      this.logger.log(`[archiveAndResetProvinceCompanyMonthlyTreeCounts] 存档完成: 已处理 ${archivedCount} 个正式省公司`)
    } catch (error) {
      this.logger.error('[archiveAndResetProvinceCompanyMonthlyTreeCounts] 正式省公司月度树数存档失败', error)
    }
  }
}
