import { random as randomId } from "@/boxes/uid"
import { Provider } from "../../../provider/provider"
import { ProviderTransform } from "../../../provider/transform"
import { generateText } from "ai"

export interface Result {
  model: string
  access: boolean
  snippet: string
  latency: number | null
  errorType: string | null
  errorMessage: string | null
}

export async function call(
  model: Provider.Model,
  prompt: string,
  timeout: number,
  start: number,
): Promise<Omit<Result, "model">> {
  try {
    const language = await Provider.getLanguage(model)
    const sessionID = randomId()
    const options = ProviderTransform.options({ model, sessionID })
    const providerOptions = ProviderTransform.providerOptions(model, options)
    const maxOutputTokens = ProviderTransform.maxOutputTokens(model)
    const temperature = ProviderTransform.temperature(model)
    const topP = ProviderTransform.topP(model)
    const topK = ProviderTransform.topK(model)
    const messages: Parameters<typeof generateText>[0]["messages"] = [{ role: "user", content: prompt }]
    const transformed = ProviderTransform.message(messages, model, options)
    const result = await generateText({
      model: language,
      messages: transformed,
      abortSignal: AbortSignal.timeout(timeout),
      maxOutputTokens,
      temperature,
      topP,
      topK,
      providerOptions,
    })

    return {
      access: true,
      snippet: result.text.replace(/\n/g, " "),
      latency: Date.now() - start,
      errorType: null,
      errorMessage: null,
    }
  } catch (cause) {
    const err = classifyError(cause)
    return {
      access: false,
      snippet: "",
      latency: Date.now() - start,
      errorType: err.type,
      errorMessage: err.message,
    }
  }
}

function classifyError(cause: unknown) {
  if (
    cause instanceof Error &&
    (cause.name === "AbortError" || cause.message.includes("abort") || cause.message.includes("timeout"))
  ) {
    return { type: "timeout", message: "The operation timed out." }
  }

  if (typeof cause === "object" && cause && "error" in cause) {
    const data = cause.error as { type?: unknown; message?: unknown }
    if (typeof data.type === "string" || typeof data.message === "string") {
      return {
        type: typeof data.type === "string" ? data.type : "api_error",
        message: typeof data.message === "string" ? data.message : cause instanceof Error ? cause.message : "API error",
      }
    }
  }

  if (cause instanceof Error) return { type: "unknown", message: cause.message }
  return { type: "unknown", message: "An unknown error occurred" }
}
