import type { FillRateMetrics } from './fillRateMonitor.js';

export interface FillRateControllerConfig {
  // 目标 KPI
  targetFillsPerMinute: number;     // 目标成交率（次/分钟）
  targetMakerRatio: number;         // 目标 maker 占比 (0-1)
  maxSelfTradeRatio: number;        // 最大自成交占比 (0-1)

  // PI 控制器参数（调整 ΔP - grid step）
  kp_step: number;                  // 比例增益
  ki_step: number;                  // 积分增益

  // PI 控制器参数（调整 Q - clip size）
  kp_clip: number;                  // 比例增益
  ki_clip: number;                  // 积分增益

  // 调整范围限制
  minGridStepBps: number;           // 最小网格间距
  maxGridStepBps: number;           // 最大网格间距
  minClipUsd: number;               // 最小订单金额
  maxClipUsd: number;               // 最大订单金额

  // 安全阈值
  minMakerRatioForAdjust: number;   // maker 占比低于此值时，强制放宽间距
  emergencyStepMultiplier: number;  // 紧急模式下的步长倍数（如 1.5x）
}

export interface ControlOutput {
  gridStepBps: number;              // 建议的网格间距
  clipUsd: number;                  // 建议的订单金额
  emergencyMode: boolean;           // 是否进入紧急模式（maker占比过低）
  reason: string;                   // 调整原因
}

/**
 * 基于成交率 KPI 的 PI 控制器
 *
 * 控制逻辑：
 * - 成交率低 → 收窄 ΔP（订单更靠近盘口）
 * - 成交率高 → 放宽 ΔP（避免过度成交和自成交）
 * - Maker 占比低 → 强制放宽 ΔP + 减小 Q（降低 taker 成本）
 * - 自成交率高 → 减小 Q（降低单笔订单量）
 */
export class FillRateController {
  private readonly config: FillRateControllerConfig;

  // 积分项（累积误差）
  private fillRateErrorIntegral: number = 0;
  private clipErrorIntegral: number = 0;

  // 上次控制输出（用于平滑调整）
  private lastGridStepBps: number;
  private lastClipUsd: number;

  constructor(config: FillRateControllerConfig) {
    this.config = config;
    this.lastGridStepBps = (config.minGridStepBps + config.maxGridStepBps) / 2;
    this.lastClipUsd = (config.minClipUsd + config.maxClipUsd) / 2;
  }

  /**
   * 根据当前成交率指标计算控制输出
   */
  compute(metrics: FillRateMetrics): ControlOutput {
    const {
      targetFillsPerMinute,
      targetMakerRatio,
      maxSelfTradeRatio,
      kp_step,
      ki_step,
      kp_clip,
      ki_clip,
      minGridStepBps,
      maxGridStepBps,
      minClipUsd,
      maxClipUsd,
      minMakerRatioForAdjust,
      emergencyStepMultiplier
    } = this.config;

    // 1. 检查是否需要进入紧急模式（maker 占比过低）
    const emergencyMode = metrics.makerRatio < minMakerRatioForAdjust;

    if (emergencyMode) {
      // 紧急模式：强制放宽间距，减小订单量
      const emergencyStepBps = Math.min(
        this.lastGridStepBps * emergencyStepMultiplier,
        maxGridStepBps
      );
      const emergencyClipUsd = Math.max(
        this.lastClipUsd * 0.7,  // 减小到 70%
        minClipUsd
      );

      // 重置积分项
      this.fillRateErrorIntegral = 0;
      this.clipErrorIntegral = 0;

      this.lastGridStepBps = emergencyStepBps;
      this.lastClipUsd = emergencyClipUsd;

      return {
        gridStepBps: emergencyStepBps,
        clipUsd: emergencyClipUsd,
        emergencyMode: true,
        reason: `Emergency: maker ratio ${(metrics.makerRatio * 100).toFixed(1)}% < ${(minMakerRatioForAdjust * 100).toFixed(1)}%`
      };
    }

    // 2. 计算成交率误差（正值 = 成交不足，需要收窄间距）
    const fillRateError = targetFillsPerMinute - metrics.fillsPerMinute;
    this.fillRateErrorIntegral += fillRateError;

    // 积分项限幅（防止积分饱和）
    const maxIntegral = 50;
    this.fillRateErrorIntegral = Math.max(-maxIntegral, Math.min(maxIntegral, this.fillRateErrorIntegral));

    // 3. PI 控制器计算 ΔP 调整量
    // fillRateError > 0 → 成交不足 → 减小 ΔP（收窄，更靠近盘口）
    // fillRateError < 0 → 成交过多 → 增大 ΔP（放宽，远离盘口）
    const stepAdjustment = -(kp_step * fillRateError + ki_step * this.fillRateErrorIntegral);
    let newGridStepBps = this.lastGridStepBps + stepAdjustment;
    newGridStepBps = Math.max(minGridStepBps, Math.min(maxGridStepBps, newGridStepBps));

    // 4. 基于自成交率调整订单量
    // selfTradeRatio 高 → 减小 Q
    let newClipUsd = this.lastClipUsd;

    if (metrics.selfTradeRatio > maxSelfTradeRatio) {
      const clipError = metrics.selfTradeRatio - maxSelfTradeRatio;
      this.clipErrorIntegral += clipError;
      this.clipErrorIntegral = Math.max(-10, Math.min(10, this.clipErrorIntegral));

      const clipAdjustment = -(kp_clip * clipError + ki_clip * this.clipErrorIntegral) * this.lastClipUsd;
      newClipUsd = this.lastClipUsd + clipAdjustment;
      newClipUsd = Math.max(minClipUsd, Math.min(maxClipUsd, newClipUsd));
    }

    // 5. 平滑调整（限制单次变化幅度）
    const maxStepChangeRatio = 0.2;  // 最大 20% 变化
    const maxClipChangeRatio = 0.15; // 最大 15% 变化

    const stepChangeBounded = Math.max(
      this.lastGridStepBps * (1 - maxStepChangeRatio),
      Math.min(this.lastGridStepBps * (1 + maxStepChangeRatio), newGridStepBps)
    );

    const clipChangeBounded = Math.max(
      this.lastClipUsd * (1 - maxClipChangeRatio),
      Math.min(this.lastClipUsd * (1 + maxClipChangeRatio), newClipUsd)
    );

    // 更新状态
    this.lastGridStepBps = stepChangeBounded;
    this.lastClipUsd = clipChangeBounded;

    // 6. 生成调整原因
    let reason = 'Normal operation';
    if (Math.abs(fillRateError) > 5) {
      reason = fillRateError > 0
        ? `Low fill rate (${metrics.fillsPerMinute.toFixed(1)} < ${targetFillsPerMinute}) → tightening grid`
        : `High fill rate (${metrics.fillsPerMinute.toFixed(1)} > ${targetFillsPerMinute}) → widening grid`;
    }
    if (metrics.selfTradeRatio > maxSelfTradeRatio) {
      reason += ` | High self-trade ratio (${(metrics.selfTradeRatio * 100).toFixed(1)}%) → reducing clip`;
    }

    return {
      gridStepBps: stepChangeBounded,
      clipUsd: clipChangeBounded,
      emergencyMode: false,
      reason
    };
  }

  /**
   * 重置控制器状态
   */
  reset(initialStepBps?: number, initialClipUsd?: number): void {
    this.fillRateErrorIntegral = 0;
    this.clipErrorIntegral = 0;

    if (initialStepBps !== undefined) {
      this.lastGridStepBps = initialStepBps;
    }
    if (initialClipUsd !== undefined) {
      this.lastClipUsd = initialClipUsd;
    }
  }

  /**
   * 获取当前状态
   */
  getStatus() {
    return {
      lastGridStepBps: this.lastGridStepBps,
      lastClipUsd: this.lastClipUsd,
      fillRateErrorIntegral: this.fillRateErrorIntegral,
      clipErrorIntegral: this.clipErrorIntegral
    };
  }
}
