import type {
  StandardizationSourceSnapshot,
} from "../core/types.ts";
import { resolveTextPrompt } from "../internal/prompt-runtime.js";
import {
  COMBINED_STANDARDIZATION_PROMPT_KEY,
  buildCombinedStandardizationUserMessageFromSource,
} from "./combined-standardization-contract.ts";

export const OFFLINE_STANDARDIZATION_THRESHOLD = 10;

type OfflineBatchRequestLine = {
  custom_id: string;
  method: "POST";
  url: "/v4/chat/completions";
  body: {
    model: string;
    messages: Array<{ role: "system" | "user"; content: string }>;
    temperature: number;
    response_format: { type: "json_object" };
  };
};

const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
const OFFLINE_CUSTOM_ID_PREFIX = "v1";

function encodeUuidForOfflineCustomId(uuid: string): string {
  const normalized = uuid.trim().toLowerCase();
  if (!UUID_PATTERN.test(normalized)) {
    throw new Error(`无效的 UUID，无法生成离线 Batch custom_id: ${uuid}`);
  }

  return Buffer.from(normalized.replace(/-/g, ""), "hex").toString("base64url");
}

function decodeUuidFromOfflineCustomId(token: string): string | null {
  try {
    const hex = Buffer.from(token, "base64url").toString("hex");
    if (hex.length !== 32 || /[^0-9a-f]/i.test(hex)) {
      return null;
    }

    const uuid = `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
    return UUID_PATTERN.test(uuid) ? uuid : null;
  } catch {
    return null;
  }
}

export function buildOfflineBatchCustomId(taskId: string, materialId: string): string {
  return `${OFFLINE_CUSTOM_ID_PREFIX}_${encodeUuidForOfflineCustomId(taskId)}_${encodeUuidForOfflineCustomId(materialId)}`;
}

export function parseOfflineBatchCustomId(customId: string) {
  const normalized = customId.trim();
  const compactMatch = new RegExp(`^${OFFLINE_CUSTOM_ID_PREFIX}_([A-Za-z0-9_-]{22})_([A-Za-z0-9_-]{22})$`).exec(normalized);
  if (compactMatch) {
    const taskId = decodeUuidFromOfflineCustomId(compactMatch[1]!);
    const materialId = decodeUuidFromOfflineCustomId(compactMatch[2]!);
    if (!taskId || !materialId) {
      return null;
    }

    return {
      taskId,
      materialId,
    };
  }

  const legacyMatch = /^(.+):([0-9a-f-]+)$/i.exec(normalized);
  if (!legacyMatch) {
    return null;
  }

  return {
    taskId: legacyMatch[1]!,
    materialId: legacyMatch[2]!,
  };
}

export function buildOfflineBatchUserMessage(source: StandardizationSourceSnapshot): string {
  return buildCombinedStandardizationUserMessageFromSource(source);
}

async function resolveOfflineStandardizationSystemPrompt(model: string): Promise<string> {
  const prompt = await resolveTextPrompt(COMBINED_STANDARDIZATION_PROMPT_KEY, {
    provider: process.env.PROMPT_PROVIDER || process.env.LLM_PROVIDER || "*",
    model: model || process.env.LLM_MODEL || "*",
  });

  return prompt.text;
}

export async function buildOfflineBatchRequestLines(params: {
  taskId: string;
  model: string;
  sources: StandardizationSourceSnapshot[];
}): Promise<OfflineBatchRequestLine[]> {
  const systemPrompt = await resolveOfflineStandardizationSystemPrompt(params.model);

  return params.sources.map((source) => ({
    custom_id: buildOfflineBatchCustomId(params.taskId, source.id),
    method: "POST",
    url: "/v4/chat/completions",
    body: {
      model: params.model,
      messages: [
        { role: "system", content: systemPrompt },
        { role: "user", content: buildOfflineBatchUserMessage(source) },
      ],
      temperature: 0.1,
      response_format: { type: "json_object" },
    },
  }));
}

export async function buildOfflineBatchJsonl(params: {
  taskId: string;
  model: string;
  sources: StandardizationSourceSnapshot[];
}): Promise<string> {
  const lines = await buildOfflineBatchRequestLines(params);

  return lines
    .map((line) => JSON.stringify(line))
    .join("\n");
}