import { Effect } from "effect"
import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi"
import { InstanceHttpApi } from "../api"
import * as GPU from "@/provider/local/gpu"
import * as Hub from "@/provider/local/hub"
import * as Manager from "@/provider/local/model-manager"
import * as Orchestrator from "@/provider/local/orchestrator"
import * as RAG from "@/provider/local/rag"
import type { ModelArtifact } from "@/provider/local/types"

function toArtifact(payload: { repo: string; filename: string; format: string; quantization: string; sizeBytes: number; sha256?: string }): ModelArtifact {
  return Hub.buildArtifact(payload.repo, payload.filename, payload.sizeBytes, payload.sha256)
}

export const localHandlers = HttpApiBuilder.group(InstanceHttpApi, "local", (handlers) =>
  Effect.gen(function* () {
    const gpu = Effect.fn("LocalHttpApi.gpu")(function* () {
      return yield* GPU.profile
    })

    const backends = Effect.fn("LocalHttpApi.backends")(function* () {
      return yield* Effect.promise(() => Orchestrator.detectBackends())
    })

    const models = Effect.fn("LocalHttpApi.models")(function* () {
      return yield* Effect.promise(() => Manager.list())
    })

    const instances = Effect.fn("LocalHttpApi.instances")(function* () {
      return Orchestrator.runningInstances()
    })

    const hubSearch = Effect.fn("LocalHttpApi.hubSearch")(function* (ctx: { requestSearchParams: { q: string; limit?: string } }) {
      return yield* Effect.promise(() => Hub.search(ctx.requestSearchParams.q, { limit: Number(ctx.requestSearchParams.limit ?? "20") }))
    })

    const ragRecommend = Effect.fn("LocalHttpApi.ragRecommend")(function* (ctx: { requestSearchParams: { vramMB: string } }) {
      return yield* Effect.promise(() => RAG.recommendForVRAM(Number(ctx.requestSearchParams.vramMB)))
    })

    const install = Effect.fn("LocalHttpApi.install")(function* (ctx: { payload: { repo: string; filename: string; format: string; quantization: string; sizeBytes: number; sha256?: string } }) {
      const artifact = toArtifact(ctx.payload)
      return yield* Effect.promise(() => Manager.install(artifact))
    })

    const uninstall = Effect.fn("LocalHttpApi.uninstall")(function* (ctx: { payload: { repo: string; filename: string; format: string; quantization: string; sizeBytes: number; sha256?: string } }) {
      const artifact = toArtifact(ctx.payload)
      yield* Effect.promise(() => Manager.uninstall(artifact))
      return true
    })

    const load = Effect.fn("LocalHttpApi.load")(function* (ctx: { payload: { repo: string; filename: string; backend?: string; gpuIndex?: number } }) {
      // Find or create artifact from installed models
      const installed = yield* Effect.promise(() => Manager.list())
      const match = installed.find((m) => m.repo === ctx.payload.repo && m.filename === ctx.payload.filename)
      if (!match) {
        return yield* Effect.fail(new HttpApiError.BadRequest({}))
      }
      const artifact = Hub.buildArtifact(ctx.payload.repo, ctx.payload.filename, match.sizeBytes)
      return yield* Effect.promise(() => Orchestrator.load(artifact, { backend: ctx.payload.backend as any, gpuIndex: ctx.payload.gpuIndex }))
    })

    const unload = Effect.fn("LocalHttpApi.unload")(function* (ctx: { payload: { instanceId: string } }) {
      yield* Effect.promise(() => Orchestrator.unload(ctx.payload.instanceId))
      return true
    })

    const ragInstall = Effect.fn("LocalHttpApi.ragInstall")(function* (ctx: { payload: { id: string; repo: string; type: string } }) {
      const allEmbeddings = RAG.EMBEDDING_MODELS
      const allRerankers = RAG.RERANKER_MODELS
      const emb = allEmbeddings.find((m) => m.id === ctx.payload.id)
      if (emb) {
        return yield* Effect.promise(() => RAG.installEmbedding(emb))
      }
      const reranker = allRerankers.find((m) => m.id === ctx.payload.id)
      if (reranker) {
        return yield* Effect.promise(() => RAG.installReranker(reranker))
      }
      return yield* Effect.fail(new HttpApiError.BadRequest({}))
    })

    return handlers
      .handle("gpu", gpu)
      .handle("backends", backends)
      .handle("models", models)
      .handle("instances", instances)
      .handle("hub_search", hubSearch)
      .handle("rag_recommend", ragRecommend)
      .handle("install", install)
      .handle("uninstall", uninstall)
      .handle("load", load)
      .handle("unload", unload)
      .handle("rag_install", ragInstall)
  }),
)
