import { isLevelEnabled, writeLog } from "./logger.js";

const TEXT_PREVIEW_LIMIT = 120;
const ERROR_PREVIEW_LIMIT = 200;

function normalizeSpace(value) {
  return String(value ?? "").replace(/\s+/g, " ").trim();
}

function previewText(value, limit = TEXT_PREVIEW_LIMIT) {
  const normalized = normalizeSpace(value);
  return normalized.length > limit ? `${normalized.slice(0, limit)}...` : normalized;
}

function approximateDataUrlBytes(url) {
  const match = String(url ?? "").match(/^data:([^;,]+)?(;base64)?,([\s\S]*)$/);
  if (!match) {
    return null;
  }

  const payload = match[3] ?? "";
  if (match[2]) {
    return Math.floor((payload.replace(/\s/g, "").length * 3) / 4);
  }
  return Buffer.byteLength(decodeURIComponent(payload), "utf8");
}

function summarizeUrl(url) {
  const value = String(url ?? "");
  const dataUrlMatch = value.match(/^data:([^;,]+)?(;base64)?,/);
  if (dataUrlMatch) {
    return {
      kind: "data_url",
      mimeType: dataUrlMatch[1] || "application/octet-stream",
      approxBytes: approximateDataUrlBytes(value),
    };
  }

  if (!value) {
    return { kind: "empty" };
  }

  try {
    const parsed = new URL(value);
    return {
      kind: "url",
      origin: parsed.origin,
      pathnamePreview: previewText(parsed.pathname, 80),
    };
  } catch {
    return {
      kind: "text",
      preview: previewText(value, 80),
    };
  }
}

function summarizeMediaBlock(block) {
  const type = String(block?.type ?? "unknown");
  if (type === "image_url") {
    return {
      type,
      url: summarizeUrl(block?.image_url?.url),
    };
  }

  if (type === "file") {
    return {
      type,
      filename: previewText(block?.file?.filename ?? "", 80),
      fileData: summarizeUrl(block?.file?.file_data),
    };
  }

  return { type };
}

function summarizeContent(content) {
  if (typeof content === "string") {
    return {
      contentType: "text",
      textLength: content.length,
      textPreview: previewText(content),
      media: [],
    };
  }

  if (Array.isArray(content)) {
    let textLength = 0;
    const textPreviews = [];
    const media = [];
    const blockTypes = [];

    for (const block of content) {
      const type = String(block?.type ?? "unknown");
      blockTypes.push(type);
      if (type === "text") {
        const text = String(block?.text ?? "");
        textLength += text.length;
        if (textPreviews.join(" ").length < TEXT_PREVIEW_LIMIT) {
          textPreviews.push(text);
        }
      } else {
        media.push(summarizeMediaBlock(block));
      }
    }

    return {
      contentType: "parts",
      partCount: content.length,
      blockTypes,
      textLength,
      textPreview: previewText(textPreviews.join(" ")),
      media,
    };
  }

  if (content == null) {
    return {
      contentType: "empty",
      textLength: 0,
      textPreview: "",
      media: [],
    };
  }

  return {
    contentType: typeof content,
    textLength: 0,
    textPreview: "",
    media: [],
  };
}

function summarizeMessages(messages) {
  return Array.isArray(messages)
    ? messages.map((message) => ({
        role: String(message?.role ?? "unknown"),
        ...summarizeContent(message?.content),
      }))
    : [];
}

function summarizeRequest(request) {
  return {
    endpoint: request?.endpoint,
    url: request?.url,
    filename: request?.filename,
    contentLength: request?.contentLength,
    inputFileId: request?.inputFileId,
    batchId: request?.batchId,
    model: request?.model,
    temperature: request?.temperature,
    response_format: request?.response_format,
    max_tokens: request?.max_tokens,
    messages: summarizeMessages(request?.messages),
  };
}

function extractResponseContent(response) {
  return response?.choices?.[0]?.message?.content
    ?? response?.choices?.[0]?.text
    ?? "";
}

function summarizeResponse(response) {
  const content = extractResponseContent(response)
    || (response && !response.choices ? JSON.stringify(response) : "");
  return {
    textLength: String(content ?? "").length,
    textPreview: previewText(content),
    finish_reason: response?.choices?.[0]?.finish_reason,
    usage: response?.usage,
  };
}

function summarizeError(error) {
  const status = error?.status ?? error?.response?.status;
  const code = error?.code ?? error?.type;
  const responseText = error?.response?.data ?? error?.response?.body ?? error?.body;
  return {
    name: error instanceof Error ? error.name : typeof error,
    message: previewText(error instanceof Error ? error.message : String(error), ERROR_PREVIEW_LIMIT),
    status,
    code,
    responsePreview: responseText == null ? "" : previewText(responseText, ERROR_PREVIEW_LIMIT),
  };
}

function normalizeContext(context = {}) {
  return {
    scope: context.scope ?? "automation",
    stage: context.stage ?? "unknown",
    label: context.label ?? "unknown",
    provider: context.provider ?? "",
    model: context.model ?? "",
  };
}

function writeLlmDebugEvent(event, context, payload) {
  if (!isLevelEnabled("debug")) {
    return;
  }

  writeLog("debug", JSON.stringify({
    event,
    ...normalizeContext(context),
    ...payload,
  }));
}

function logLlmRequest(context, request) {
  writeLlmDebugEvent("llm.request", context, {
    input: summarizeRequest(request),
  });
}

function logLlmResponse(context, startedAt, response) {
  writeLlmDebugEvent("llm.response", context, {
    durationMs: Date.now() - startedAt,
    output: summarizeResponse(response),
  });
}

function logLlmError(context, startedAt, error) {
  writeLlmDebugEvent("llm.error", context, {
    durationMs: Date.now() - startedAt,
    error: summarizeError(error),
  });
}

async function runWithLlmDebugLog(context, request, operation) {
  const startedAt = Date.now();
  logLlmRequest(context, request);
  try {
    const response = await operation();
    logLlmResponse(context, startedAt, response);
    return response;
  } catch (error) {
    logLlmError(context, startedAt, error);
    throw error;
  }
}

export {
  logLlmError,
  logLlmRequest,
  logLlmResponse,
  previewText,
  runWithLlmDebugLog,
  summarizeContent,
  summarizeError,
  summarizeMessages,
  summarizeRequest,
  summarizeResponse,
  summarizeUrl,
};
