import { Schema } from "effect"
import { HttpApi, HttpApiEndpoint, HttpApiError, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
import { Authorization } from "../middleware/authorization"
import { InstanceContextMiddleware } from "../middleware/instance-context"
import { WorkspaceRoutingMiddleware } from "../middleware/workspace-routing"
import { described } from "./metadata"
import {
  GPUProfile, BackendStatus, ModelInstance,
  RAGAsset, HFModelSearch,
} from "@/provider/local/types"

const root = "/local"

// Request schemas
const InstallPayload = Schema.Struct({
  repo: Schema.String,
  filename: Schema.String,
  format: Schema.String,
  quantization: Schema.String,
  sizeBytes: Schema.Number,
  sha256: Schema.optional(Schema.String),
})
const LoadPayload = Schema.Struct({
  repo: Schema.String,
  filename: Schema.String,
  backend: Schema.optional(Schema.String),
  gpuIndex: Schema.optional(Schema.Number),
})
const UnloadPayload = Schema.Struct({ instanceId: Schema.String })
const InstallRAGPayload = Schema.Struct({ id: Schema.String, repo: Schema.String, type: Schema.String })
const InstalledModel = Schema.Struct({ repo: Schema.String, filename: Schema.String, path: Schema.String, sizeBytes: Schema.Number })
const RAGRecommendResult = Schema.Struct({ embeddings: Schema.Array(RAGAsset), rerankers: Schema.Array(RAGAsset) })

export const LocalApi = HttpApi.make("local")
  .add(
    HttpApiGroup.make("local")
      .add(
        HttpApiEndpoint.get("gpu", `${root}/gpu`, {
          success: described(GPUProfile, "GPU profile with VRAM info"),
        }).annotateMerge(OpenApi.annotations({ identifier: "local.gpu", summary: "Get GPU profile" })),
        HttpApiEndpoint.get("backends", `${root}/backends`, {
          success: described(Schema.Array(BackendStatus), "Detected local backends"),
        }).annotateMerge(OpenApi.annotations({ identifier: "local.backends", summary: "List detected backends" })),
        HttpApiEndpoint.get("models", `${root}/models`, {
          success: described(Schema.Array(InstalledModel), "Installed local models"),
        }).annotateMerge(OpenApi.annotations({ identifier: "local.models", summary: "List installed models" })),
        HttpApiEndpoint.get("instances", `${root}/instances`, {
          success: described(Schema.Array(ModelInstance), "Running model instances"),
        }).annotateMerge(OpenApi.annotations({ identifier: "local.instances", summary: "List running instances" })),
        HttpApiEndpoint.get("hub_search", `${root}/hub/search`, {
          requestSearchParams: Schema.Struct({ q: Schema.String, limit: Schema.String }),
          success: described(Schema.Array(HFModelSearch), "Search results from HuggingFace Hub"),
        }).annotateMerge(OpenApi.annotations({ identifier: "local.hub.search", summary: "Search HuggingFace Hub" })),
        HttpApiEndpoint.get("rag_recommend", `${root}/rag/recommend`, {
          requestSearchParams: Schema.Struct({ vramMB: Schema.String }),
          success: described(RAGRecommendResult, "RAG recommendations"),
        }).annotateMerge(OpenApi.annotations({ identifier: "local.rag.recommend", summary: "Get RAG model recommendations" })),
        HttpApiEndpoint.post("install", `${root}/models/install`, {
          payload: InstallPayload,
          success: described(Schema.String, "Installed file path"),
          error: HttpApiError.BadRequest,
        }).annotateMerge(OpenApi.annotations({ identifier: "local.install", summary: "Install model from HuggingFace" })),
        HttpApiEndpoint.post("uninstall", `${root}/models/uninstall`, {
          payload: InstallPayload,
          success: described(Schema.Boolean, "Success"),
        }).annotateMerge(OpenApi.annotations({ identifier: "local.uninstall", summary: "Uninstall a local model" })),
        HttpApiEndpoint.post("load", `${root}/instances/load`, {
          payload: LoadPayload,
          success: described(ModelInstance, "Started model instance"),
          error: HttpApiError.BadRequest,
        }).annotateMerge(OpenApi.annotations({ identifier: "local.load", summary: "Load and start a model" })),
        HttpApiEndpoint.post("unload", `${root}/instances/unload`, {
          payload: UnloadPayload,
          success: described(Schema.Boolean, "Success"),
        }).annotateMerge(OpenApi.annotations({ identifier: "local.unload", summary: "Stop a running model" })),
        HttpApiEndpoint.post("rag_install", `${root}/rag/install`, {
          payload: InstallRAGPayload,
          success: described(Schema.String, "Installed path"),
          error: HttpApiError.BadRequest,
        }).annotateMerge(OpenApi.annotations({ identifier: "local.rag.install", summary: "Install RAG asset" })),
      )
      .annotateMerge(OpenApi.annotations({ title: "local", description: "Local model management API" }))
      .middleware(InstanceContextMiddleware)
      .middleware(WorkspaceRoutingMiddleware)
      .middleware(Authorization),
  )
  .annotateMerge(OpenApi.annotations({ title: "saeeol local models", version: "0.0.1" }))
