import OpenAI from "openai";
import { CORRECT_CITY_SCHEMA, CORRECT_CITY_SYSTEM, buildUserMessage, usageCostUsd } from "./prompt.js";

export const name = "openai";

// Per-million-token rates. Verify against https://openai.com/api/pricing/
// Cached input pricing is OpenAI's automatic prompt-cache discount (50% off
// when the same prompt prefix is seen within ~5-10 minutes; no client config).
export const pricingByModel = {
  "gpt-4o-mini": { inputUsdPerM: 0.15,  outputUsdPerM: 0.60,  cacheWriteUsdPerM: 0,    cacheReadUsdPerM: 0.075 },
  "gpt-4o":      { inputUsdPerM: 2.50,  outputUsdPerM: 10.00, cacheWriteUsdPerM: 0,    cacheReadUsdPerM: 1.25  },
  "gpt-4.1-mini":{ inputUsdPerM: 0.40,  outputUsdPerM: 1.60,  cacheWriteUsdPerM: 0,    cacheReadUsdPerM: 0.10  },
  "gpt-4.1":     { inputUsdPerM: 2.00,  outputUsdPerM: 8.00,  cacheWriteUsdPerM: 0,    cacheReadUsdPerM: 0.50  },
};

export const defaultModel = "gpt-4o-mini";

export function activeModel() {
  return process.env.OPENAI_MODEL || defaultModel;
}

export function isAvailable() {
  return Boolean(process.env.OPENAI_API_KEY);
}

let _client = null;
function getClient() {
  if (_client) return _client;
  _client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
  return _client;
}

const TOOL = {
  type: "function",
  function: {
    name: "correct_city",
    description: "Pick the closest matching US city/town/CDP name from the provided list for the user's input, or return null if nothing reasonable matches.",
    parameters: CORRECT_CITY_SCHEMA,
  },
};

export async function correctCity({ city, stateCode, candidates }) {
  const model = activeModel();
  const pricing = pricingByModel[model] || { inputUsdPerM: 0, outputUsdPerM: 0, cacheWriteUsdPerM: 0, cacheReadUsdPerM: 0 };
  const resp = await getClient().chat.completions.create({
    model,
    messages: [
      { role: "system", content: CORRECT_CITY_SYSTEM },
      { role: "user", content: buildUserMessage({ city, stateCode, candidates }) },
    ],
    tools: [TOOL],
    tool_choice: { type: "function", function: { name: TOOL.function.name } },
    max_tokens: 200,
  });
  const call = resp.choices?.[0]?.message?.tool_calls?.[0];
  if (!call?.function?.arguments) throw new Error("OpenAI did not return a tool call");
  const input = JSON.parse(call.function.arguments);
  const u = resp.usage || {};
  const cached = u.prompt_tokens_details?.cached_tokens ?? 0;
  const usage = {
    input_tokens:                Math.max(0, Number(u.prompt_tokens ?? 0) - cached),
    output_tokens:               Number(u.completion_tokens ?? 0),
    cache_creation_input_tokens: 0,
    cache_read_input_tokens:     Number(cached),
  };
  return {
    provider: name,
    model,
    correctedCityName: input.correctedCityName ?? null,
    confidence: input.confidence ?? "low",
    reasoning: input.reasoning ?? "",
    usage,
    costUsd: usageCostUsd(usage, pricing),
    pricingPerMTok: {
      input: pricing.inputUsdPerM,
      output: pricing.outputUsdPerM,
      cacheWrite: pricing.cacheWriteUsdPerM,
      cacheRead: pricing.cacheReadUsdPerM,
    },
  };
}
