import z from "zod"
import {
  type IndexingTelemetryEvent,
} from "@saeeol/indexing/engine"
import { toIndexingConfigInput, type IndexingConfig } from "@saeeol/indexing/config"
import { Telemetry } from "@saeeol/telemetry"
import { fetchSaeeolEmbeddingModelCatalog } from "@saeeol/gateway"
import { Config } from "@/config/config"
import { Auth } from "@/auth"
import {
  IndexingStatus,
  disabledIndexingStatus,
} from "@saeeol/indexing/status"
import * as Log from "@saeeol/core/util/log"
import { type SaeeolIndexingAuth, resolveSaeeolIndexingAuth } from "./indexing-auth"

const log = Log.create({ service: "saeeol-indexing" })

function missing() {
  return disabledIndexingStatus("Indexing plugin is not enabled for this workspace.")
}

function noWorkspace() {
  return disabledIndexingStatus("Codebase indexing is disabled because no workspace folder is open in VS Code.")
}

function worktreeDisabled(): z.infer<typeof IndexingStatus> {
  return {
    state: "Disabled",
    message: "Indexing is disabled in worktree sessions. Use the main workspace for indexing.",
    processedFiles: 0,
    totalFiles: 0,
    percent: 0,
  }
}

function isWorktreePath(dir: string): boolean {
  return /(?:\/|\\)\.saeeol(?:code)?(?:\/|\\)worktrees(?:\/|\\)/.test(dir)
}

function failed(err: unknown): z.infer<typeof IndexingStatus> {
  const msg = err instanceof Error ? err.message : String(err)
  const text = msg.startsWith("Failed to initialize:") ? msg : `Failed to initialize: ${msg}`

  return {
    state: "Error",
    message: text,
    processedFiles: 0,
    totalFiles: 0,
    percent: 0,
  }
}

function pending(): z.infer<typeof IndexingStatus> {
  return {
    state: "In Progress",
    message: "Indexing is initializing.",
    processedFiles: 0,
    totalFiles: 0,
    percent: 0,
  }
}

async function saeeolAuth(cfg: Awaited<ReturnType<typeof Config.get>>): Promise<SaeeolIndexingAuth> {
  const auth = await Auth.get("saeeol")
  return resolveSaeeolIndexingAuth({ config: cfg, auth })
}

function enrichSaeeol(input: ReturnType<typeof toIndexingConfigInput>, auth: SaeeolIndexingAuth) {
  if (input.embedderProvider !== "saeeol") return input

  return {
    ...input,
    saeeolApiKey: input.saeeolApiKey ?? auth.apiKey,
    saeeolBaseUrl: input.saeeolBaseUrl ?? auth.baseUrl,
    saeeolOrganizationId: input.saeeolOrganizationId ?? auth.organizationId,
  }
}

async function model(input: ReturnType<typeof toIndexingConfigInput>, auth: SaeeolIndexingAuth) {
  if (input.embedderProvider !== "saeeol") return input
  if (input.modelId && input.modelDimension) return input

  const catalog = await fetchSaeeolEmbeddingModelCatalog({ baseURL: auth.baseUrl, token: auth.apiKey })
  const id = input.modelId ? (catalog.aliases[input.modelId] ?? input.modelId) : catalog.defaultModel
  const found = catalog.models.find((item) => item.id === id)
  if (!found) return { ...input, modelId: id || input.modelId }

  return {
    ...input,
    modelId: found.id,
    modelDimension: input.modelDimension ?? found.dimension,
    searchMinScore: input.searchMinScore ?? found.scoreThreshold,
  }
}

function trackTelemetry(event: IndexingTelemetryEvent): void {
  if (event.type === "started") {
    Telemetry.trackIndexingStarted({
      trigger: event.trigger,
      source: event.source,
      mode: event.mode,
      provider: event.provider,
      vectorStore: event.vectorStore,
      modelId: event.modelId,
    })
    return
  }

  if (event.type === "completed") {
    Telemetry.trackIndexingCompleted({
      trigger: event.trigger,
      source: event.source,
      mode: event.mode,
      provider: event.provider,
      vectorStore: event.vectorStore,
      modelId: event.modelId,
      filesIndexed: event.filesIndexed,
      filesDiscovered: event.filesDiscovered,
      totalBlocks: event.totalBlocks,
      batchErrors: event.batchErrors,
    })
    return
  }

  if (event.type === "file_count") {
    Telemetry.trackIndexingFileCount({
      source: event.source,
      mode: event.mode,
      provider: event.provider,
      vectorStore: event.vectorStore,
      modelId: event.modelId,
      discovered: event.discovered,
      candidate: event.candidate,
    })
    return
  }

  if (event.type === "batch_retry") {
    Telemetry.trackIndexingBatchRetry({
      source: event.source,
      mode: event.mode,
      provider: event.provider,
      vectorStore: event.vectorStore,
      modelId: event.modelId,
      attempt: event.attempt,
      maxRetries: event.maxRetries,
      batchSize: event.batchSize,
      error: event.error,
    })
    return
  }

  Telemetry.trackIndexingError({
    source: event.source,
    trigger: event.trigger,
    mode: event.mode,
    provider: event.provider,
    vectorStore: event.vectorStore,
    modelId: event.modelId,
    location: event.location,
    error: event.error,
    retryCount: event.retryCount,
    maxRetries: event.maxRetries,
  })
}

export {
  log,
  missing,
  noWorkspace,
  worktreeDisabled,
  isWorktreePath,
  failed,
  pending,
  saeeolAuth,
  enrichSaeeol,
  model,
  trackTelemetry,
}
