import { describe, expect, it } from "vitest";

import {
  PROCUREMENT_LIST_EXTRACTION_SYSTEM_PROMPT,
  buildProcurementListExtractionRequest,
  parseProcurementListExtractionPayload,
} from "./procurement-extraction-contract.ts";

const pdfRenderDataUrl = "data:image/png;base64,cGRmLXJlbmRlci1wbmc=";
const jpegDataUrl = "data:image/jpeg;base64,amVwZWctcGVyZi10YWJsZQ==";

function makeValidPayload() {
  return {
    file_profile: {
      file_type: "cad_drawing_pdf",
      document_title: "嵌缝与螺栓防水构造图",
      drawing_no: "005A",
      page_count: 1,
      diagnostics: ["文本层较少，进入视觉理解"],
    },
    purchase_objects: [
      {
        object_role: "primary_item",
        original_name: "塑料保护罩覆盖",
        recommended_name: "螺栓孔塑料保护罩",
        fields: {
          specification: "盾构区间螺栓保护罩，图号 005A",
          material_requirement: "低烟无卤原生材料",
          technical_requirement: "燃烧性能不低于 B1 级",
          test_requirement: "按 GB8624-2012 5.2.3 检测",
          technical_standard: "GB8624-2012",
          applicable_conditions: "盾构区间螺栓孔覆盖",
          main_dimensions: "适配 M30 螺栓孔",
          tolerance: "",
          performance_indicators: "密度 0.91~1.2；拉伸强度 >=16MPa；相对伸长率 90%；氧指数 >=23",
          accessory_materials: "",
          supply_form: "单件供货",
          acceptance_documents: "合格证、检测报告、材质证明",
          quantity: 130000,
          unit: "个",
          invoice_type: "13%专票",
          delivery_address: "江苏省南京市建邺区",
          remarks: "",
          pending_confirmations: ["是否包含密封胶"],
        },
        evidence: [
          {
            source_file_name: "塑料保护罩覆盖.jpeg",
            source_type: "image",
            field: "performance_indicators",
            quote: "密度 0.91~1.2、拉伸强度 >=16MPa、氧指数 >=23",
            confidence: 0.92,
          },
        ],
        warnings: ["PDF 局部尺寸需要复核"],
        confidence: 0.86,
      },
      {
        object_role: "non_procurement",
        original_name: "施工做法说明",
        recommended_name: "",
        fields: {
          specification: "",
          material_requirement: "",
          technical_requirement: "施工前清理基层",
          test_requirement: "",
          technical_standard: "",
          applicable_conditions: "",
          main_dimensions: "",
          tolerance: "",
          performance_indicators: "",
          accessory_materials: "",
          supply_form: "",
          acceptance_documents: "",
          quantity: 0,
          unit: "",
          invoice_type: "",
          delivery_address: "",
          remarks: "不是采购对象",
          pending_confirmations: [],
        },
        evidence: [],
        warnings: [],
      },
    ],
    warnings: ["图纸标题不可直接作为采购品名"],
  };
}

describe("parseProcurementListExtractionPayload", () => {
  it("parses a valid file-level contract and filters non-procurement objects", () => {
    const parsed = parseProcurementListExtractionPayload(JSON.stringify(makeValidPayload()));

    expect(parsed.file_profile).toMatchObject({
      file_type: "cad_drawing_pdf",
      drawing_no: "005A",
    });
    expect(parsed.purchase_objects).toHaveLength(1);
    expect(parsed.purchase_objects[0]).toMatchObject({
      object_role: "primary_item",
      original_name: "塑料保护罩覆盖",
      recommended_name: "螺栓孔塑料保护罩",
      fields: expect.objectContaining({
        performance_indicators: expect.stringContaining("氧指数 >=23"),
        remarks: "",
      }),
    });
    expect(parsed.warnings).toEqual(["图纸标题不可直接作为采购品名"]);
  });

  it("throws clear errors for illegal JSON, missing fields, and empty purchase objects", () => {
    expect(() => parseProcurementListExtractionPayload("not json"))
      .toThrow(/采购清单多模态模型返回内容不是合法 JSON/);

    expect(() => parseProcurementListExtractionPayload({
      file_profile: {
        document_title: "",
        drawing_no: "",
        page_count: 1,
        diagnostics: [],
      },
      purchase_objects: [{ recommended_name: "螺栓孔塑料保护罩" }],
      warnings: [],
    }))
      .toThrow(/采购清单多模态模型返回结构不符合固定 JSON 合同/);

    expect(() => parseProcurementListExtractionPayload({
      file_profile: {
        file_type: "image",
        document_title: "",
        drawing_no: "",
        page_count: 1,
        diagnostics: [],
      },
      purchase_objects: [],
      warnings: [],
    })).toThrow(/采购清单多模态提取结果为空/);
  });

  it("keeps performance indicators in structured fields instead of remarks", () => {
    const payload = makeValidPayload();
    const parsed = parseProcurementListExtractionPayload(payload);

    expect(parsed.purchase_objects[0]?.fields.performance_indicators)
      .toContain("拉伸强度 >=16MPa");
    expect(parsed.purchase_objects[0]?.fields.remarks).not.toContain("拉伸强度");
  });

  it("accepts MiMo responses that omit metadata fields but keep procurement fields", () => {
    const payload = makeValidPayload();
    delete (payload.file_profile as Partial<typeof payload.file_profile>).file_type;
    delete (payload.purchase_objects[0] as Partial<typeof payload.purchase_objects[number]>).object_role;
    delete (payload.purchase_objects[0] as Partial<typeof payload.purchase_objects[number]>).evidence;

    const parsed = parseProcurementListExtractionPayload(payload);

    expect(parsed.file_profile.file_type).toBe("unknown");
    expect(parsed.purchase_objects[0]).toMatchObject({
      object_role: "primary_item",
      evidence: [],
      recommended_name: "螺栓孔塑料保护罩",
    });
  });

  it("keeps multiple procurement objects while filtering only non-procurement objects", () => {
    const payload = makeValidPayload();
    payload.purchase_objects.splice(1, 0, {
      object_role: "accessory",
      original_name: "密封胶",
      recommended_name: "配套密封胶",
      fields: {
        specification: "与螺栓孔保护罩配套",
        material_requirement: "",
        technical_requirement: "",
        test_requirement: "",
        technical_standard: "",
        applicable_conditions: "保护罩安装配套",
        main_dimensions: "",
        tolerance: "",
        performance_indicators: "",
        accessory_materials: "",
        supply_form: "可随主件配套供货",
        acceptance_documents: "",
        quantity: 0,
        unit: "",
        invoice_type: "",
        delivery_address: "",
        remarks: "",
        pending_confirmations: ["是否单独采购"],
      },
      evidence: [],
      warnings: [],
      confidence: 0.6,
    });

    const parsed = parseProcurementListExtractionPayload(payload);

    expect(parsed.purchase_objects.map((object) => object.object_role)).toEqual([
      "primary_item",
      "accessory",
    ]);
  });
});

describe("buildProcurementListExtractionRequest", () => {
  it("builds a multimodal JSON request from PDF render images, JPEG images, and Excel rows", () => {
    const request = buildProcurementListExtractionRequest({
      model: "mimo-v2.5",
      fileProfiles: [
        {
          source_file_name: "塑料保护罩覆盖.pdf",
          file_type: "cad_drawing_pdf",
          document_title: "嵌缝与螺栓防水构造图",
          drawing_no: "005A",
          page_count: 1,
          diagnostics: ["文本层较少"],
        },
      ],
      imageInputs: [
        {
          source_file_name: "塑料保护罩覆盖.pdf",
          source_type: "pdf_render",
          label: "PDF 首页高清裁剪图",
          dataUrl: pdfRenderDataUrl,
        },
        {
          source_file_name: "塑料保护罩覆盖.jpeg",
          source_type: "image",
          label: "性能指标图",
          dataUrl: jpegDataUrl,
        },
      ],
      excelRows: [
        {
          source_file_name: "塑料保护罩覆盖.xlsx",
          row_index: 1,
          values: {
            名称: "塑料保护罩覆盖",
            数量: 130000,
            单位: "个",
            发票种类: "13%专票",
          },
        },
      ],
    });

    expect(request.response_format).toEqual({ type: "json_object" });
    expect(request.model).toBe("mimo-v2.5");
    expect(request.messages[0]).toEqual({
      role: "system",
      content: PROCUREMENT_LIST_EXTRACTION_SYSTEM_PROMPT,
    });

    const userContent = request.messages[1]?.content;
    expect(userContent).toEqual([
      { type: "image_url", image_url: { url: pdfRenderDataUrl } },
      { type: "image_url", image_url: { url: jpegDataUrl } },
      expect.objectContaining({
        type: "text",
        text: expect.stringContaining("塑料保护罩覆盖.xlsx"),
      }),
    ]);
    expect(userContent.at(-1)).toMatchObject({
      type: "text",
      text: expect.stringContaining("不要把图纸标题直接当采购品名"),
    });
  });

  it("includes the required procurement-drawing prompt rules", () => {
    expect(PROCUREMENT_LIST_EXTRACTION_SYSTEM_PROMPT).toContain("不把图纸标题直接当采购品名");
    expect(PROCUREMENT_LIST_EXTRACTION_SYSTEM_PROMPT).toContain("区分主采购件、配套材料、施工做法、安装对象、非采购对象");
    expect(PROCUREMENT_LIST_EXTRACTION_SYSTEM_PROMPT).toContain("保留工程符号");
    expect(PROCUREMENT_LIST_EXTRACTION_SYSTEM_PROMPT).toContain("不确定信息进入待确认");
  });
});
