/**
 * @file 配置管理器 + Scanner 配置
 * @description 提供全局配置管理功能 + Scanner v2.0 配置接口
 * @module core/config
 */

// ============================================================
// 原有 ConfigManager（保持向后兼容）
// ============================================================

export class ConfigManager {
  private static instance: ConfigManager;
  private config: Record<string, any> = {};
  private changeCallbacks: Map<string, Array<(value: any, oldValue: any) => void>> = new Map();
  private initialized = false;

  private constructor() {
    this._resetDefaults();
  }

  public static getInstance(): ConfigManager {
    if (!ConfigManager.instance) {
      ConfigManager.instance = new ConfigManager();
    }
    return ConfigManager.instance;
  }

  public static resetInstance(): void {
    ConfigManager.instance = undefined as any;
  }

  private _resetDefaults(): void {
    this.config = {
      debug: false,
      logLevel: 'info',
      modelPath: '/models',
      maxRetries: 3,
      retryDelay: 1000,
      detectionInterval: 100,
      face: {
        enabled: true,
        confidenceThreshold: 0.5,
        maxFaces: 10,
      },
      idCard: {
        enabled: false,
      },
      qr: {
        enabled: false,
      },
    };
    this.initialized = true;
  }

  public get<T = any>(key: string, defaultValue?: T): T {
    const keys = key.split('.');
    let value: any = this.config;
    for (const k of keys) {
      value = value?.[k];
    }
    return (value !== undefined ? value : defaultValue) as T;
  }

  public set(key: string, value: any): void {
    const keys = key.split('.');
    let target: any = this.config;
    for (let i = 0; i < keys.length - 1; i++) {
      if (!target[keys[i]]) target[keys[i]] = {};
      target = target[keys[i]];
    }
    const oldValue = target[keys[keys.length - 1]];
    target[keys[keys.length - 1]] = value;
    const callbacks = this.changeCallbacks.get(key);
    if (callbacks) {
      callbacks.forEach(cb => cb(value, oldValue));
    }
  }

  public onChange(key: string, callback: (value: any, oldValue: any) => void): void {
    if (!this.changeCallbacks.has(key)) {
      this.changeCallbacks.set(key, []);
    }
    this.changeCallbacks.get(key)!.push(callback);
  }

  /** @deprecated Use onChange instead */
  public onConfigChange<T = any>(key: string, callback: (value: T, oldValue: T) => void): void {
    this.onChange(key, callback);
  }

  public removeChangeCallback(key: string, callback: (value: any, oldValue: any) => void): void {
    const callbacks = this.changeCallbacks.get(key);
    if (callbacks) {
      const index = callbacks.indexOf(callback);
      if (index > -1) callbacks.splice(index, 1);
    }
  }

  public reset(): void {
    this.config = {};
    this._resetDefaults();
  }
}

// ============================================================
// Scanner v2.0 配置接口
// ============================================================

/**
 * Scanner configuration interface (v2.0)
 */
export interface ScannerConfig {
  debug?: boolean;
  modules?: {
    face?: boolean;
    faceComparator?: boolean;
    faceLiveness?: boolean;
    idCard?: boolean;
    qr?: boolean;
  };
  performance?: {
    maxCanvasWidth?: number;
    useWorker?: boolean;
    lazyLoad?: boolean;
  };
}

/**
 * Scanner module interface
 * All modules must implement this interface
 */
export interface ScannerModule {
  initialize(): Promise<void>;
  destroy(): Promise<void>;
}

/**
 * Image source types
 */
export type ImageSource = HTMLVideoElement | HTMLCanvasElement | HTMLImageElement | ImageData | string;

/**
 * Face detection result
 */
export interface Face {
  box: {
    x: number;
    y: number;
    width: number;
    height: number;
  };
  confidence: number;
  keypoints?: {
    leftEye?: { x: number; y: number };
    rightEye?: { x: number; y: number };
    nose?: { x: number; y: number };
    leftMouth?: { x: number; y: number };
    rightMouth?: { x: number; y: number };
  };
  embedding?: number[];
}

/**
 * Module configuration
 */
export interface ModuleConfig {
  enabled?: boolean;
  [key: string]: any;
}
