import { describe, it, expect, vi, beforeEach } from "vitest";
import express from "express";
import supertest from "supertest";

// Mock voicePipelineService BEFORE importing voice routes
vi.mock("../services/voice-pipeline.js", () => ({
  voicePipelineService: vi.fn(() => ({
    transcribe: vi.fn().mockResolvedValue({ text: "Hello world", language: "en" }),
    synthesize: vi.fn().mockResolvedValue(Buffer.from("fake-wav-audio")),
    formatForVoice: vi.fn((t: string) => t),
    transcodeToWav16k: vi.fn().mockResolvedValue(Buffer.from("wav-data")),
  })),
}));

// Mock assertBoard to be a no-op (board auth passes)
vi.mock("../routes/authz.js", () => ({
  assertBoard: vi.fn(),
}));

import { voiceRoutes } from "../routes/voice.js";

function buildApp() {
  const app = express();
  app.use(express.json());

  // Attach a mock actor so assertBoard sees board type
  app.use((req: any, _res: any, next: any) => {
    req.actor = { type: "board" };
    next();
  });

  app.use(voiceRoutes());
  return app;
}

describe("POST /transcribe", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("returns 200 with { text, language } for valid audio upload", async () => {
    const app = buildApp();
    const fakeAudio = Buffer.from("fake-audio-bytes");

    const res = await supertest(app)
      .post("/transcribe")
      .attach("audio", fakeAudio, { filename: "audio.webm", contentType: "audio/webm" });

    expect(res.status).toBe(200);
    expect(res.body).toHaveProperty("text");
    expect(res.body.text).toBe("Hello world");
  });

  it("returns 400 when audio field is missing", async () => {
    const app = buildApp();

    const res = await supertest(app)
      .post("/transcribe")
      .send({});

    expect(res.status).toBe(400);
    expect(res.body).toEqual({ error: "Missing audio field" });
  });
});

describe("POST /synthesize", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("returns 200 with audio/wav content-type for valid text", async () => {
    const app = buildApp();

    const res = await supertest(app)
      .post("/synthesize")
      .send({ text: "Hello" });

    expect(res.status).toBe(200);
    expect(res.headers["content-type"]).toMatch(/audio\/wav/);
  });

  it("returns 400 when text is missing", async () => {
    const app = buildApp();

    const res = await supertest(app)
      .post("/synthesize")
      .send({});

    expect(res.status).toBe(400);
    expect(res.body).toEqual({ error: "text is required" });
  });

  it("returns 400 when text is not a string", async () => {
    const app = buildApp();

    const res = await supertest(app)
      .post("/synthesize")
      .send({ text: 42 });

    expect(res.status).toBe(400);
    expect(res.body).toEqual({ error: "text is required" });
  });
});
