/**
 * @file 人脸比对器
 * @description 提供人脸特征向量比对功能
 * @module modules/face/face-comparator
 */

import { FaceDetectionResult } from '../../interfaces/face-detection';
import { Result } from '../../core/result';
import { FaceComparisonError } from '../../core/errors';
import { Logger } from '../../core/logger';

/**
 * 人脸比对结果
 */
export interface ComparisonResult {
  /** 相似度 (0-1) */
  similarity: number;
  /** 是否匹配（基于阈值） */
  isMatch: boolean;
  /** 使用的阈值 */
  threshold: number;
}

/**
 * 人脸比对器配置
 */
export interface FaceComparatorConfig {
  /** 人脸匹配阈值 (0-1) */
  matchThreshold?: number;
}

/**
 * 人脸比对器
 *
 * 负责计算两个人脸特征向量的相似度
 */
export class FaceComparator {
  /** 日志记录器 */
  private logger: Logger;

  /** 匹配阈值 */
  private matchThreshold: number;

  /**
   * 构造函数
   * @param config 比对器配置
   */
  constructor(config: FaceComparatorConfig = {}) {
    this.logger = Logger.getInstance();
    this.matchThreshold = config.matchThreshold ?? 0.6;
  }

  /**
   * 计算两个特征向量的余弦相似度
   *
   * @param v1 特征向量1
   * @param v2 特征向量2
   * @returns 相似度 (0-1)
   */
  computeSimilarity(v1: number[], v2: number[]): number {
    if (v1.length !== v2.length) {
      throw new Error('特征向量维度不匹配');
    }

    let dotProduct = 0;
    let norm1 = 0;
    let norm2 = 0;

    for (let i = 0; i < v1.length; i++) {
      dotProduct += v1[i] * v2[i];
      norm1 += v1[i] * v1[i];
      norm2 += v2[i] * v2[i];
    }

    // 确保长度非零
    if (norm1 === 0 || norm2 === 0) {
      return 0;
    }

    return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
  }

  /**
   * 比对两个人脸
   *
   * @param source 源人脸（特征向量或检测结果）
   * @param target 目标人脸（特征向量或检测结果）
   * @returns 比对结果
   */
  compare(
    source: number[] | FaceDetectionResult,
    target: number[] | FaceDetectionResult
  ): Result<ComparisonResult> {
    try {
      // 提取特征向量
      const sourceEmbedding = this.extractEmbedding(source);
      const targetEmbedding = this.extractEmbedding(target);

      if (!sourceEmbedding || !targetEmbedding) {
        return Result.failure(new FaceComparisonError('无法获取特征向量'));
      }

      // 计算相似度
      const similarity = this.computeSimilarity(sourceEmbedding, targetEmbedding);
      const isMatch = similarity >= this.matchThreshold;

      return Result.success({
        similarity,
        isMatch,
        threshold: this.matchThreshold
      });
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.logger.error('FaceComparator', `人脸比对失败: ${errorMessage}`, error as Error);
      return Result.failure(new FaceComparisonError(`人脸比对失败: ${errorMessage}`));
    }
  }

  /**
   * 从输入中提取特征向量
   */
  private extractEmbedding(input: number[] | FaceDetectionResult): number[] | null {
    if (Array.isArray(input)) {
      return input;
    }

    if (input.embedding?.vector) {
      return input.embedding.vector;
    }

    return null;
  }

  /**
   * 设置匹配阈值
   */
  setThreshold(threshold: number): void {
    if (threshold < 0 || threshold > 1) {
      throw new Error('阈值必须在 0-1 范围内');
    }
    this.matchThreshold = threshold;
  }

  /**
   * 获取当前阈值
   */
  getThreshold(): number {
    return this.matchThreshold;
  }
}
