import { Provide, Scope, ScopeEnum, Inject, Logger } from '@midwayjs/core';
import type { ILogger } from '@midwayjs/logger';
import type { DesktopTask, TaskResult, AdapterContext } from './types.js';
import { SafetyGuard } from './safety_guard.js';
import { AdapterRegistry } from './adapters/registry.js';
import { WindowLocator } from './window_locator.js';
import { NodeScreenshooter } from './screenshot.js';
import { InputController } from './input.js';
import { VlmClient } from './vlm_client.js';
import { ActionExecutor } from './action_executor.js';
import { getParser } from './parser/registry.js';

/**
 * Desktop Op 核心运行时 — adapter 主导的 ReAct 拓扑
 *
 * 执行流程：
 *   1. 检查 AbortSignal 是否已中止
 *   2. safetyGuard.validateTaskShape 校验任务结构
 *   3. safetyGuard.validateAppId 校验应用白名单
 *   4. adapterRegistry.get 获取适配器
 *   5. adapter.findWindow 查找目标窗口（null 则抛 window-not-found）
 *   6. windowLocator.activate 激活窗口 + 500ms 稳定等待
 *   7. 再次检查 AbortSignal
 *   8. 构建 AdapterContext（ctx）
 *   9. adapter.preFlightCheck 前置状态校验
 *  10. 再次检查 AbortSignal
 *  11. adapter.buildSteps 生成动作序列
 *  12. 逐步执行：validateAction → execute → jitter 延迟（200~800ms）
 *  13. 再次检查 AbortSignal
 *  14. adapter.verifyResult 验证操作结果（false 则抛 verify-failed）
 *  15. 返回 TaskResult
 */
@Provide()
@Scope(ScopeEnum.Singleton)
export class DesktopOpRuntime {
  @Inject() safetyGuard!: SafetyGuard;
  @Inject() adapterRegistry!: AdapterRegistry;
  @Inject() windowLocator!: WindowLocator;
  @Inject() screenshooter!: NodeScreenshooter;
  @Inject() input!: InputController;
  @Inject() vlm!: VlmClient;
  @Inject() actionExecutor!: ActionExecutor;
  @Logger() logger!: ILogger;

  /**
   * 执行一个桌面任务
   *
   * @param task  — 待执行的任务描述
   * @param abort — 外部中止信号，任意阶段检查到中止则抛 Error('aborted: <reason>')
   * @returns TaskResult（ok, modelCalls, steps, durationMs）
   */
  async runTask(task: DesktopTask, abort: AbortSignal): Promise<TaskResult> {
    const startedAt = Date.now();

    // 阶段 1：开始前检查中止信号
    this.checkAbort(abort);

    // 阶段 2-3：安全校验
    this.safetyGuard.validateTaskShape(task);
    this.safetyGuard.validateAppId(task.appId);

    // 阶段 4：获取适配器
    const adapter = this.adapterRegistry.get(task.appId);

    // 阶段 5：查找目标窗口
    const win = await adapter.findWindow(task.target);
    if (!win) throw new Error('window-not-found');

    // 阶段 6：激活窗口并等待 500ms 让系统稳定
    await this.windowLocator.activate(win);
    await this.delay(500);

    // 阶段 7：再次检查中止
    this.checkAbort(abort);

    // 阶段 8：构建适配器上下文，供 preFlightCheck / verifyResult 使用
    // ActionExecutor 依赖 InputController，每次 runTask 均重设（幂等）
    this.actionExecutor.setInput(this.input);

    const ctx: AdapterContext = {
      window: win,
      screenshot: this.screenshooter,
      input: this.input,
      vlm: this.vlm,
      // MVP 默认使用 volcengine parser；Layer 2 可按 modelChannel.supplier 动态选择
      parser: getParser('volcengine'),
      logger: this.logger,
      task,
      modelCalls: 0,
    };

    // 阶段 9：前置检查（验证当前应用状态是否满足执行条件）
    await adapter.preFlightCheck(task, ctx);

    // 阶段 10：再次检查中止
    this.checkAbort(abort);

    // 阶段 11：构建动作序列
    const steps = await adapter.buildSteps(task);

    // 阶段 12：逐步执行每个动作
    let stepCount = 0;
    for (const step of steps) {
      // 每步前检查中止
      this.checkAbort(abort);
      // 安全护栏校验（拦截危险操作）
      this.safetyGuard.validateAction(step);
      // 执行动作
      await this.actionExecutor.execute(step);
      // 加入随机抖动延迟，避免操作过快被检测或引发竞态
      await this.delay(this.jitter(200, 800));
      stepCount++;
    }

    // 阶段 13：步骤执行完毕后再次检查中止
    this.checkAbort(abort);

    // 阶段 14：验证操作结果
    const ok = await adapter.verifyResult(task, ctx);
    if (!ok) throw new Error('verify-failed');

    // 阶段 15：返回任务结果
    return {
      ok: true,
      modelCalls: ctx.modelCalls,
      steps: stepCount,
      durationMs: Date.now() - startedAt,
    };
  }

  /**
   * 检查中止信号，已中止则抛出带原因的 Error
   */
  private checkAbort(abort: AbortSignal): void {
    if (abort.aborted) {
      const reason = (abort as any).reason;
      const msg =
        typeof reason === 'string'
          ? reason
          : reason?.message ?? 'aborted';
      throw new Error('aborted: ' + msg);
    }
  }

  /**
   * 延迟指定毫秒（兼容 jest 假计时器）
   */
  private delay(ms: number): Promise<void> {
    return new Promise(r => setTimeout(r, ms));
  }

  /**
   * 返回 [min, max) 区间内的随机整数毫秒（步骤间抖动延迟）
   */
  private jitter(min: number, max: number): number {
    return Math.floor(min + Math.random() * (max - min));
  }
}
