/**
 * @file 人脸检测选项工厂
 * @description 创建 face-api 检测选项和处理选项
 * @module modules/face/face-detector-options
 */

import * as faceapi from '@vladmandic/face-api';
import { FaceDetectionOptions } from '../../interfaces/face-detection';
import { FaceModelType, FaceDetectorConfig } from './face-detector';

/**
 * 人脸检测选项工厂
 *
 * 负责创建 face-api 兼容的检测选项和处理选项
 */
export class FaceDetectorOptionsFactory {
  /**
   * 创建 face-api 检测选项
   * @param detectionModel 检测模型类型
   * @param minConfidence 最小置信度
   * @returns face-api 检测选项
   */
  static createFaceAPIOptions(
    detectionModel: FaceModelType,
    minConfidence: number
  ): faceapi.SsdMobilenetv1Options | faceapi.TinyFaceDetectorOptions | faceapi.MtcnnOptions {
    switch (detectionModel) {
      case FaceModelType.SSD_MOBILENET:
        return new faceapi.SsdMobilenetv1Options({ minConfidence });
      case FaceModelType.TINY_FACE:
        return new faceapi.TinyFaceDetectorOptions({ scoreThreshold: minConfidence });
      case FaceModelType.MTCNN:
        return new faceapi.MtcnnOptions({ minConfidence });
      default:
        return new faceapi.SsdMobilenetv1Options({ minConfidence });
    }
  }

  /**
   * 合并检测选项和配置
   * @param config 人脸检测器配置
   * @param options 用户提供的选项
   * @returns 合并后的检测选项
   */
  static mergeOptions(
    config: FaceDetectorConfig,
    options: FaceDetectionOptions = {}
  ): FaceDetectionOptions {
    return {
      minConfidence: config.minConfidence,
      maxFaces: config.maxFaces,
      withLandmarks: config.detectLandmarks,
      withAttributes: config.detectExpressions || config.detectAgeGender,
      withEmbedding: config.extractEmbeddings,
      enableTracking: config.enableTracking,
      ...options
    };
  }

  /**
   * 执行人脸检测
   * @param input 输入图像/视频/画布
   * @param faceapiOptions face-api 检测选项
   * @param detectOptions 检测选项
   * @param landmarksModel 关键点模型类型
   * @returns face-api 检测结果
   */
  static async detect(
    input: HTMLImageElement | HTMLCanvasElement | HTMLVideoElement,
    faceapiOptions: faceapi.SsdMobilenetv1Options | faceapi.TinyFaceDetectorOptions | faceapi.MtcnnOptions,
    detectOptions: FaceDetectionOptions,
    landmarksModel: 'tiny' | '68_points'
  ): Promise<any> {
    const withLandmarks = detectOptions.withLandmarks;
    const withAttributes = detectOptions.withAttributes;
    const withEmbedding = detectOptions.withEmbedding;

    // 根据选项组合选择检测方法链
    if (withLandmarks && withAttributes && withEmbedding) {
      // 全功能检测
      return await faceapi
        .detectAllFaces(input, faceapiOptions)
        .withFaceLandmarks(landmarksModel === 'tiny')
        .withFaceExpressions()
        .withAgeAndGender()
        .withFaceDescriptors();
    } else if (withLandmarks && withAttributes) {
      // 检测带关键点和属性
      return await faceapi
        .detectAllFaces(input, faceapiOptions)
        .withFaceLandmarks(landmarksModel === 'tiny')
        .withFaceExpressions()
        .withAgeAndGender();
    } else if (withLandmarks) {
      // 检测带关键点
      return await faceapi
        .detectAllFaces(input, faceapiOptions)
        .withFaceLandmarks(landmarksModel === 'tiny');
    } else {
      // 仅检测
      return await faceapi.detectAllFaces(input, faceapiOptions);
    }
  }
}
