"use strict";

import { cleanFilePath } from "../utils/fileUtils.js";

/**
 * Service for Speaker Identification functionality
 */
export class SpeakerIdService {
  initialized = false;
  embeddingDim = 0;
  constructor(api) {
    this.api = api;
  }

  /**
   * Get the embedding dimension
   */
  getEmbeddingDim() {
    return this.embeddingDim;
  }

  /**
   * Validate that the Sherpa-ONNX library is properly loaded
   * @returns Promise that resolves with validation result
   */
  validateLibrary() {
    return this.api.validateLibraryLoaded();
  }

  /**
   * Initialize Speaker ID with the provided model configuration
   * @param config Configuration for Speaker ID model
   * @returns Promise that resolves with initialization result
   */
  async init(config) {
    try {
      // First validate library is loaded
      const validateResult = await this.validateLibrary();
      if (!validateResult.loaded) {
        return {
          success: false,
          embeddingDim: 0,
          error: validateResult.status || 'Library not loaded'
        };
      }
      const cleanedConfig = {
        ...config,
        modelDir: cleanFilePath(config.modelDir)
      };
      const result = await this.api.initSpeakerId(cleanedConfig);
      if (result.success) {
        this.initialized = true;
        this.embeddingDim = result.embeddingDim;
      }
      return result;
    } catch (error) {
      return {
        success: false,
        embeddingDim: 0,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Process audio samples for speaker identification
   * @param sampleRate Sample rate of the audio
   * @param samples Audio samples as number array
   * @returns Promise that resolves with processing result
   */
  async processSamples(sampleRate, samples) {
    try {
      if (!this.initialized) {
        return {
          success: false,
          samplesProcessed: 0,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.processSpeakerIdSamples({
        sampleRate,
        samples
      });
    } catch (error) {
      return {
        success: false,
        samplesProcessed: 0,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Compute speaker embedding from processed audio
   * @returns Promise that resolves with embedding result
   */
  async computeEmbedding() {
    try {
      if (!this.initialized) {
        return {
          success: false,
          durationMs: 0,
          embedding: [],
          embeddingDim: 0,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.computeSpeakerEmbedding();
    } catch (error) {
      return {
        success: false,
        durationMs: 0,
        embedding: [],
        embeddingDim: 0,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Reset the incremental speaker embedding stream without releasing the model.
   * Useful after a failed live turn so the next turn starts from a clean buffer.
   */
  async resetStream() {
    try {
      if (!this.initialized) {
        return {
          success: false,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.resetSpeakerIdStream();
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Register a speaker with the given name and embedding
   * @param name Name of the speaker to register
   * @param embedding Speaker's embedding vector
   * @returns Promise that resolves with registration result
   */
  async registerSpeaker(name, embedding) {
    try {
      if (!this.initialized) {
        return {
          success: false,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.registerSpeaker({
        name,
        embedding
      });
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Remove a speaker from the database
   * @param name Name of the speaker to remove
   * @returns Promise that resolves with removal result
   */
  async removeSpeaker(name) {
    try {
      if (!this.initialized) {
        return {
          success: false,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.removeSpeaker(name);
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Get all registered speakers
   * @returns Promise that resolves with speakers result
   */
  async getSpeakers() {
    try {
      if (!this.initialized) {
        return {
          success: false,
          speakers: [],
          count: 0,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.getSpeakers();
    } catch (error) {
      return {
        success: false,
        speakers: [],
        count: 0,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Identify a speaker based on embedding
   * @param embedding Speaker embedding vector
   * @param threshold Similarity threshold (0-1), default: 0.5
   * @returns Promise that resolves with identification result
   */
  async identifySpeaker(embedding, threshold = 0.5) {
    try {
      if (!this.initialized) {
        return {
          success: false,
          speakerName: '',
          identified: false,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.identifySpeaker({
        embedding,
        threshold
      });
    } catch (error) {
      return {
        success: false,
        speakerName: '',
        identified: false,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Verify if the embedding matches a specific speaker
   * @param name Name of the speaker to verify
   * @param embedding Speaker embedding vector
   * @param threshold Similarity threshold (0-1), default: 0.5
   * @returns Promise that resolves with verification result
   */
  async verifySpeaker(name, embedding, threshold = 0.5) {
    try {
      if (!this.initialized) {
        return {
          success: false,
          verified: false,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.verifySpeaker({
        name,
        embedding,
        threshold
      });
    } catch (error) {
      return {
        success: false,
        verified: false,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Process audio file to create embedding
   * @param filePath Path to the audio file
   * @returns Promise that resolves with file processing result
   */
  async processFile(filePath) {
    try {
      if (!this.initialized) {
        return {
          success: false,
          durationMs: 0,
          embedding: [],
          embeddingDim: 0,
          sampleRate: 0,
          samples: 0,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.processSpeakerIdFile(cleanFilePath(filePath));
    } catch (error) {
      return {
        success: false,
        durationMs: 0,
        embedding: [],
        embeddingDim: 0,
        sampleRate: 0,
        samples: 0,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }
  async processFileWindow(filePath, startTimeMs, durationMs) {
    try {
      if (!this.initialized) {
        return {
          success: false,
          durationMs: 0,
          embedding: [],
          embeddingDim: 0,
          sampleRate: 0,
          samples: 0,
          startTimeMs,
          windowDurationMs: durationMs,
          error: 'Speaker ID is not initialized'
        };
      }
      return await this.api.processSpeakerIdFileWindow({
        filePath: cleanFilePath(filePath),
        startTimeMs,
        durationMs
      });
    } catch (error) {
      return {
        success: false,
        durationMs: 0,
        embedding: [],
        embeddingDim: 0,
        sampleRate: 0,
        samples: 0,
        startTimeMs,
        windowDurationMs: durationMs,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Full speaker identification flow from audio file
   * @param filePath Path to the audio file
   * @param threshold Similarity threshold (0-1), default: 0.5
   * @returns Promise that resolves with identification result
   */
  async identifyFromFile(filePath, threshold = 0.5) {
    try {
      if (!this.initialized) {
        return {
          success: false,
          speakerName: '',
          identified: false,
          error: 'Speaker ID is not initialized'
        };
      }

      // Process the file to get embedding
      const processResult = await this.processFile(filePath);
      if (!processResult.success) {
        return {
          success: false,
          speakerName: '',
          identified: false,
          error: processResult.error
        };
      }

      // Identify the speaker using the embedding
      return await this.identifySpeaker(processResult.embedding, threshold);
    } catch (error) {
      return {
        success: false,
        speakerName: '',
        identified: false,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Register a speaker from audio file
   * @param name Name of the speaker to register
   * @param filePath Path to the audio file
   * @returns Promise that resolves with registration result
   */
  async registerFromFile(name, filePath) {
    try {
      if (!this.initialized) {
        return {
          success: false,
          error: 'Speaker ID is not initialized'
        };
      }

      // Process the file to get embedding
      const processResult = await this.processFile(filePath);
      if (!processResult.success) {
        return {
          success: false,
          error: processResult.error
        };
      }

      // Register the speaker using the embedding
      return await this.registerSpeaker(name, processResult.embedding);
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  /**
   * Release Speaker ID resources
   * @returns Promise that resolves with release result
   */
  async release() {
    try {
      const result = await this.api.releaseSpeakerId();
      if (result.released) {
        this.initialized = false;
        this.embeddingDim = 0;
      }
      return result;
    } catch (error) {
      console.error('Error releasing Speaker ID resources:', error);
      return {
        released: false
      };
    }
  }
}
//# sourceMappingURL=SpeakerIdService.js.map