/**
 * TTS Provider Factory Unit Tests
 *
 * Tests the factory that creates and registers TTS providers based on config.
 *
 * Issue #391
 */

import { describe, it, expect, vi } from "vitest";
import { createTTSProviders } from "./tts-provider.factory";
import type { SpeechConfig } from "../speech.config";
import type { SpeechTier } from "../interfaces/speech-types";

// ==========================================
// Mock OpenAI SDK
// ==========================================

vi.mock("openai", () => {
  class MockOpenAI {
    audio = {
      speech: {
        create: vi.fn(),
      },
    };
  }
  return { default: MockOpenAI };
});

// ==========================================
// Test helpers
// ==========================================

function createTestConfig(overrides?: Partial<SpeechConfig>): SpeechConfig {
  return {
    stt: {
      enabled: false,
      baseUrl: "http://speaches:8000/v1",
      model: "whisper",
      language: "en",
    },
    tts: {
      default: {
        enabled: false,
        url: "http://kokoro-tts:8880/v1",
        voice: "af_heart",
        format: "mp3",
      },
      premium: {
        enabled: false,
        url: "http://chatterbox-tts:8881/v1",
      },
      fallback: {
        enabled: false,
        url: "http://openedai-speech:8000/v1",
      },
    },
    limits: {
      maxUploadSize: 25_000_000,
      maxDurationSeconds: 600,
      maxTextLength: 4096,
    },
    ...overrides,
  };
}

describe("createTTSProviders", () => {
  // ==========================================
  // Empty map when nothing enabled
  // ==========================================

  describe("when no TTS tiers are enabled", () => {
    it("should return an empty map", () => {
      const config = createTestConfig();
      const providers = createTTSProviders(config);

      expect(providers).toBeInstanceOf(Map);
      expect(providers.size).toBe(0);
    });
  });

  // ==========================================
  // Default tier
  // ==========================================

  describe("when default tier is enabled", () => {
    it("should create a provider for the default tier", () => {
      const config = createTestConfig({
        tts: {
          default: {
            enabled: true,
            url: "http://kokoro-tts:8880/v1",
            voice: "af_heart",
            format: "mp3",
          },
          premium: { enabled: false, url: "" },
          fallback: { enabled: false, url: "" },
        },
      });

      const providers = createTTSProviders(config);

      expect(providers.size).toBe(1);
      expect(providers.has("default")).toBe(true);

      const provider = providers.get("default");
      expect(provider).toBeDefined();
      expect(provider?.tier).toBe("default");
      expect(provider?.name).toBe("kokoro");
    });
  });

  // ==========================================
  // Premium tier
  // ==========================================

  describe("when premium tier is enabled", () => {
    it("should create a provider for the premium tier", () => {
      const config = createTestConfig({
        tts: {
          default: { enabled: false, url: "", voice: "", format: "" },
          premium: {
            enabled: true,
            url: "http://chatterbox-tts:8881/v1",
          },
          fallback: { enabled: false, url: "" },
        },
      });

      const providers = createTTSProviders(config);

      expect(providers.size).toBe(1);
      expect(providers.has("premium")).toBe(true);

      const provider = providers.get("premium");
      expect(provider).toBeDefined();
      expect(provider?.tier).toBe("premium");
      expect(provider?.name).toBe("chatterbox");
    });
  });

  // ==========================================
  // Fallback tier
  // ==========================================

  describe("when fallback tier is enabled", () => {
    it("should create a provider for the fallback tier", () => {
      const config = createTestConfig({
        tts: {
          default: { enabled: false, url: "", voice: "", format: "" },
          premium: { enabled: false, url: "" },
          fallback: {
            enabled: true,
            url: "http://openedai-speech:8000/v1",
          },
        },
      });

      const providers = createTTSProviders(config);

      expect(providers.size).toBe(1);
      expect(providers.has("fallback")).toBe(true);

      const provider = providers.get("fallback");
      expect(provider).toBeDefined();
      expect(provider?.tier).toBe("fallback");
      expect(provider?.name).toBe("piper");
    });
  });

  // ==========================================
  // Multiple tiers
  // ==========================================

  describe("when multiple tiers are enabled", () => {
    it("should create providers for all enabled tiers", () => {
      const config = createTestConfig({
        tts: {
          default: {
            enabled: true,
            url: "http://kokoro-tts:8880/v1",
            voice: "af_heart",
            format: "mp3",
          },
          premium: {
            enabled: true,
            url: "http://chatterbox-tts:8881/v1",
          },
          fallback: {
            enabled: true,
            url: "http://openedai-speech:8000/v1",
          },
        },
      });

      const providers = createTTSProviders(config);

      expect(providers.size).toBe(3);
      expect(providers.has("default")).toBe(true);
      expect(providers.has("premium")).toBe(true);
      expect(providers.has("fallback")).toBe(true);
    });

    it("should create providers only for enabled tiers", () => {
      const config = createTestConfig({
        tts: {
          default: {
            enabled: true,
            url: "http://kokoro-tts:8880/v1",
            voice: "af_heart",
            format: "mp3",
          },
          premium: { enabled: false, url: "" },
          fallback: {
            enabled: true,
            url: "http://openedai-speech:8000/v1",
          },
        },
      });

      const providers = createTTSProviders(config);

      expect(providers.size).toBe(2);
      expect(providers.has("default")).toBe(true);
      expect(providers.has("premium")).toBe(false);
      expect(providers.has("fallback")).toBe(true);
    });
  });

  // ==========================================
  // Provider properties
  // ==========================================

  describe("provider properties", () => {
    it("should implement ITTSProvider interface methods", () => {
      const config = createTestConfig({
        tts: {
          default: {
            enabled: true,
            url: "http://kokoro-tts:8880/v1",
            voice: "af_heart",
            format: "mp3",
          },
          premium: { enabled: false, url: "" },
          fallback: { enabled: false, url: "" },
        },
      });

      const providers = createTTSProviders(config);
      const provider = providers.get("default");

      expect(provider).toBeDefined();
      expect(typeof provider?.synthesize).toBe("function");
      expect(typeof provider?.listVoices).toBe("function");
      expect(typeof provider?.isHealthy).toBe("function");
    });

    it("should return providers as a Map<SpeechTier, ITTSProvider>", () => {
      const config = createTestConfig({
        tts: {
          default: {
            enabled: true,
            url: "http://kokoro-tts:8880/v1",
            voice: "af_heart",
            format: "mp3",
          },
          premium: { enabled: false, url: "" },
          fallback: { enabled: false, url: "" },
        },
      });

      const providers = createTTSProviders(config);

      // Verify the map keys are valid SpeechTier values
      for (const [tier] of providers) {
        expect(["default", "premium", "fallback"]).toContain(tier as SpeechTier);
      }
    });
  });
});
