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

const llmMocks = vi.hoisted(() => ({
  generateValidatedJson: vi.fn(),
}));

vi.mock("../../../lib/llm/client", async () => {
  const actual = await vi.importActual<typeof import("../../../lib/llm/client")>(
    "../../../lib/llm/client",
  );
  return {
    ...actual,
    generateValidatedJson: llmMocks.generateValidatedJson,
  };
});

import { POST as optimizeCopy } from "../copy/renwei-optimize/route";

describe("renwei copy optimization API route", () => {
  const originalApiKey = process.env.API_ACCESS_KEY;
  const originalAuthDisabled = process.env.API_AUTH_DISABLED;

  beforeEach(() => {
    process.env.API_ACCESS_KEY = "test-key";
    process.env.API_AUTH_DISABLED = "false";
  });

  afterEach(() => {
    process.env.API_ACCESS_KEY = originalApiKey;
    process.env.API_AUTH_DISABLED = originalAuthDisabled;
    llmMocks.generateValidatedJson.mockReset();
  });

  it("rejects requests without the access key", async () => {
    const response = await optimizeCopy(
      request(
        {
          source_text: "这是一段普通文案。",
          intensity: "light",
        },
        { apiKey: null },
      ),
    );

    expect(response.status).toBe(401);
  });

  it("returns 400 for empty source text", async () => {
    const response = await optimizeCopy(
      request({
        source_text: "   ",
        intensity: "light",
      }),
    );
    const body = (await response.json()) as { error: string };

    expect(response.status).toBe(400);
    expect(body.error).toBe("请输入需要优化的文案");
  });

  it("returns structured copy optimization results", async () => {
    llmMocks.generateValidatedJson.mockResolvedValueOnce({
      optimized_text: "我把这段文案顺了一下。",
      change_notes: [
        {
          original: "我把这段文案顺顺。",
          revised: "我把这段文案顺了一下。",
          reason: "修正重复表达。",
          confidence: "confident",
          revertible: false,
        },
      ],
      ai_taste_checks: [
        {
          rule_id: "promotion_tone",
          status: "pass",
          evidence: "没有新增宣传腔。",
          suggestion: "",
        },
      ],
      warnings: [],
    });

    const response = await optimizeCopy(
      request({
        source_text: "我把这段文案顺顺。",
        goal: "",
        intensity: "light",
        user_instructions: "保留口语。",
        publish_target: "朋友圈",
      }),
    );
    const body = (await response.json()) as {
      case: { id: string; case_type: string };
      result_version: { id: string; version: number };
      result: { optimized_text: string; change_notes: unknown[] };
    };

    expect(response.status).toBe(200);
    expect(body.case.case_type).toBe("human_copy");
    expect(body.result_version.version).toBe(1);
    expect(body.result.optimized_text).toBe("我把这段文案顺了一下。");
    expect(body.result.change_notes).toHaveLength(1);
    expect(llmMocks.generateValidatedJson).toHaveBeenCalledWith(
      expect.objectContaining({
        task: "renwei_copy_optimizer",
      }),
    );
  });

  it("saves LLM failures as failed human-copy cases", async () => {
    llmMocks.generateValidatedJson.mockRejectedValueOnce(
      new Error("LLM response failed schema validation: optimized_text"),
    );

    const response = await optimizeCopy(
      request({
        source_text: "这是一段普通文案。",
        intensity: "light",
        publish_target: "私域",
      }),
    );
    const body = (await response.json()) as {
      error: string;
      case?: { id: string; case_type: string };
      result_version?: { id: string; version: number };
    };

    expect(response.status).toBe(502);
    expect(body.error).toBe(
      "LLM response failed schema validation: optimized_text",
    );
    expect(body.case?.case_type).toBe("human_copy");
    expect(body.result_version?.version).toBe(1);
  });

  it("surfaces LLM failures as a 502", async () => {
    llmMocks.generateValidatedJson.mockRejectedValueOnce(
      new Error("LLM response failed schema validation: optimized_text"),
    );

    const response = await optimizeCopy(
      request({
        source_text: "这是一段普通文案。",
        intensity: "light",
      }),
    );
    const body = (await response.json()) as { error: string };

    expect(response.status).toBe(502);
    expect(body.error).toBe(
      "LLM response failed schema validation: optimized_text",
    );
  });
});

function request(body: unknown, options: { apiKey?: string | null } = {}) {
  const headers: Record<string, string> = { "content-type": "application/json" };
  const apiKey = options.apiKey === undefined ? "test-key" : options.apiKey;
  if (apiKey) {
    headers["x-api-key"] = apiKey;
  }

  return new Request("http://localhost/api/copy/renwei-optimize", {
    method: "POST",
    body: JSON.stringify(body),
    headers,
  });
}
