import { Provide, Logger, Init, Scope, ScopeEnum, App, IMidwayApplication } from '@midwayjs/core';
import { ILogger } from '@midwayjs/logger';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { CronJob } from 'cron';
import { NetaClawCrewEntity } from '../entity/crew.js';
import { NetaClawCrewRunEntity } from '../entity/crew_run.js';

/**
 * 集群定时调度器
 * 负责管理 cron 触发的集群运行
 */
@Provide()
@Scope(ScopeEnum.Singleton)
export class CrewSchedulerService {
  @Logger()
  logger: ILogger;

  @App()
  app: IMidwayApplication;

  @InjectEntityModel(NetaClawCrewEntity)
  crewRepo: Repository<NetaClawCrewEntity>;

  @InjectEntityModel(NetaClawCrewRunEntity)
  crewRunRepo: Repository<NetaClawCrewRunEntity>;

  private activeJobs = new Map<number, CronJob>();

  @Init()
  async init() {
    setTimeout(() => {
      this.restoreSchedules().catch(err =>
        this.logger.error('[CrewScheduler] 恢复定时任务失败:', err)
      );
    }, 5000);
  }

  /** 注册 cron 定时任务 */
  registerCron(crew: NetaClawCrewEntity): void {
    if (!crew.triggerConfig?.cron?.enabled) return;
    this.unregisterCron(crew.id);
    try {
      const job = new CronJob(
        crew.triggerConfig.cron.expression,
        () => {
          this.logger.info(`[CrewScheduler] 定时触发集群 ${crew.id}: ${crew.label}`);
          const callbacks = { onLog: () => {}, onTaskStatus: () => {}, onRunStatus: () => {}, onEscalation: () => {} };
          // 动态获取 orchestrator（Request 作用域），避免 Singleton 注入 Request 的限制
          this.app.getApplicationContext().getAsync('crewOrchestratorService').then((orchestrator: any) => {
            orchestrator.start(crew.id, 'cron', '', callbacks)
              .catch((err: any) => this.logger.error('[CrewScheduler] 定时运行失败:', err));
          }).catch((err: any) => this.logger.error('[CrewScheduler] 获取 orchestrator 失败:', err));
        },
        null, true,
        crew.triggerConfig.cron.timezone || 'Asia/Shanghai'
      );
      this.activeJobs.set(crew.id, job);
      this.logger.info(`[CrewScheduler] 注册定时任务: 集群 ${crew.id}, cron=${crew.triggerConfig.cron.expression}`);
    } catch (err) {
      this.logger.error('[CrewScheduler] 注册定时任务失败:', err);
    }
  }

  /** 注销 cron 定时任务 */
  unregisterCron(crewId: number): void {
    const job = this.activeJobs.get(crewId);
    if (job) {
      job.stop();
      this.activeJobs.delete(crewId);
    }
  }

  /** 恢复已发布集群的定时任务 */
  private async restoreSchedules(): Promise<void> {
    const publishedCrews = await this.crewRepo.find({ where: { status: 1 } });
    const cronCrews = publishedCrews.filter(c => c.triggerConfig?.cron?.enabled);
    this.logger.info(`[CrewScheduler] 恢复 ${cronCrews.length} 个定时任务`);
    cronCrews.forEach(crew => this.registerCron(crew));
  }

  /** 获取当前活跃定时任务数量 */
  getActiveJobCount(): number {
    return this.activeJobs.size;
  }
}
