"use server"

import { z } from "zod"
import { revalidatePath } from "next/cache"
import { createId } from "@paralleldrive/cuid2"

import type { ActionState } from "@/shared/types/action-state"
import { requirePermission, PermissionDeniedError } from "@/shared/lib/auth-guard"
import { Permissions } from "@/shared/types/permissions"
import { encryptAiApiKey, getAiErrorMessage, testAiProviderById, testAiProviderConfig } from "@/shared/lib/ai"

import {
  countDefaultAiProviders,
  createAiProvider,
  getAiProviderForUpdate,
  getAiProviderSummaries as fetchAiProviderSummaries,
  updateAiProvider,
} from "./data-access"
import type { AiProviderSummary } from "./types"

export type { AiProviderSummary } from "./types"

const ProviderSchema = z.enum(["zhipu", "openai", "gemini", "custom"])

const AiProviderFormSchema = z.object({
  id: z.string().optional(),
  provider: ProviderSchema,
  baseUrl: z.string().url().optional().or(z.literal("")),
  model: z.string().min(1),
  apiKey: z.string().min(1).optional(),
  isDefault: z.boolean().optional(),
})

const AiProviderTestSchema = AiProviderFormSchema.extend({
  apiKey: z.string().optional(),
}).superRefine((data, ctx) => {
  if (!data.apiKey?.trim() && !data.id?.trim()) {
    ctx.addIssue({
      code: z.ZodIssueCode.custom,
      path: ["apiKey"],
      message: "API key is required",
    })
  }
})

const ensureUser = async (): Promise<{ id: string }> => {
  const ctx = await requirePermission(Permissions.AI_CONFIGURE)
  return { id: ctx.userId }
}

const normalizeBaseUrl = (value: string | undefined): string | null => {
  const raw = String(value ?? "").trim()
  if (!raw.length) return null
  const trimmed = raw.replace(/\/+$/, "")
  return trimmed
    .replace(/\/v1\/chat\/completions$/i, "")
    .replace(/\/chat\/completions$/i, "")
}

export async function getAiProviderSummaries(): Promise<ActionState<AiProviderSummary[]>> {
  try {
    await ensureUser()
    const data = await fetchAiProviderSummaries()
    return { success: true, data }
  } catch (error) {
    if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
    return { success: false, message: "Failed to load AI providers" }
  }
}

export async function upsertAiProviderAction(
  data: z.infer<typeof AiProviderFormSchema>
): Promise<ActionState<string>> {
  try {
    const user = await ensureUser()
    const parsed = AiProviderFormSchema.safeParse(data)
    if (!parsed.success) {
      return { success: false, message: "Invalid form data" }
    }

    const payload = parsed.data
    const baseUrl = normalizeBaseUrl(payload.baseUrl)
    if (payload.provider !== "openai" && !baseUrl) {
      return { success: false, message: "Base URL is required for this provider" }
    }

    // Parallelize default-count and existing-provider queries
    const [defaultCount, existing] = await Promise.all([
      countDefaultAiProviders(),
      payload.id ? getAiProviderForUpdate(payload.id) : Promise.resolve(null),
    ])
    const hasDefault = defaultCount > 0

    if (payload.id) {
      const id = payload.id
      if (!existing) return { success: false, message: "AI provider not found" }

      const nextKey = payload.apiKey?.trim()
      const encrypted = nextKey ? encryptAiApiKey(nextKey) : existing.apiKeyEncrypted
      const last4 = nextKey ? nextKey.slice(-4) : existing.apiKeyLast4

      const isNextDefault =
        payload.isDefault === false && existing.isDefault && defaultCount <= 1
          ? true
          : payload.isDefault ?? existing.isDefault

      await updateAiProvider(
        id,
        {
          provider: payload.provider,
          baseUrl,
          model: payload.model,
          apiKeyEncrypted: encrypted,
          apiKeyLast4: last4,
          isDefault: isNextDefault,
          updatedBy: user.id,
        },
        payload.isDefault === true
      )

      revalidatePath("/settings")
      return { success: true, message: "AI provider updated", data: id }
    }

    if (!payload.apiKey) {
      return { success: false, message: "API key is required" }
    }

    const id = createId()
    const encrypted = encryptAiApiKey(payload.apiKey.trim())
    const last4 = payload.apiKey.trim().slice(-4)
    const shouldMakeDefault = payload.isDefault ?? !hasDefault

    await createAiProvider(
      {
        id,
        provider: payload.provider,
        baseUrl,
        model: payload.model,
        apiKeyEncrypted: encrypted,
        apiKeyLast4: last4,
        isDefault: shouldMakeDefault,
        createdBy: user.id,
        updatedBy: user.id,
      },
      shouldMakeDefault
    )

    revalidatePath("/settings")
    return { success: true, message: "AI provider created", data: id }
  } catch (error) {
    if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
    return { success: false, message: "Failed to save AI provider" }
  }
}

export async function testAiProviderAction(
  data: z.infer<typeof AiProviderTestSchema>
): Promise<ActionState<null>> {
  try {
    await ensureUser()
    const parsed = AiProviderTestSchema.safeParse(data)
    if (!parsed.success) {
      return { success: false, message: "Invalid form data" }
    }
    const payload = parsed.data
    const baseUrl = normalizeBaseUrl(payload.baseUrl)
    if (payload.provider !== "openai" && !baseUrl) {
      return { success: false, message: "Base URL is required for this provider" }
    }
    const model = payload.model.trim()
    const apiKey = payload.apiKey?.trim()
    if (apiKey) {
      await testAiProviderConfig({ apiKey, baseUrl: baseUrl ?? undefined, model })
    } else if (payload.id) {
      await testAiProviderById(payload.id, { baseUrl: baseUrl ?? undefined, model })
    }
    return { success: true, message: "AI connection ok", data: null }
  } catch (error) {
    if (error instanceof PermissionDeniedError) return { success: false, message: error.message }
    return { success: false, message: getAiErrorMessage(error) }
  }
}
