import { useCallback } from "react"
import type { AppConfig, DesktopApi, SaveConfigInput, WorkspaceSummary } from "@qjclaw/shared-types"

interface UseSaveSettingsOptions {
  config: AppConfig | null
  desktopApi: DesktopApi
  saving: boolean
  drafts: {
    lobsterKey: string
    workspacePath: string
    imageModelApiKey: string
    imageModelBaseUrl: string
    imageModelModelId: string
    videoModelApiKey: string
    videoModelBaseUrl: string
    videoModelModelId: string
    copywritingModelApiKey: string
    copywritingModelBaseUrl: string
    copywritingModelModelId: string
    digitalHumanVolcAccessKey: string
    digitalHumanVolcSecretKey: string
    digitalHumanQiniuAccessKey: string
    digitalHumanQiniuSecretKey: string
    videoAnalyzerBaseUrl: string
    videoAnalyzerModelId: string
    videoAnalyzerApiKey: string
    replicationBriefBaseUrl: string
    replicationBriefModelId: string
    replicationBriefApiKey: string
    vectcutBaseUrl: string
    vectcutFileBaseUrl: string
    vectcutApiKey: string
    xhsFeishuAppId: string
    xhsFeishuAppSecret: string
    xhsFeishuAppToken: string
    xhsFeishuTableId: string
    feishuMobileAppId: string
    feishuMobileAppSecret: string
  }
  setters: {
    setConfig(config: AppConfig): void
    setSaving(saving: boolean): void
    setErrorText(value: string): void
    setInfoText(value: string): void
    setWorkspacePathDraft(value: string): void
    setLobsterKeyDraft(value: string): void
    setImageModelApiKeyDraft(value: string): void
    setImageModelBaseUrlDraft(value: string): void
    setImageModelModelIdDraft(value: string): void
    setVideoModelApiKeyDraft(value: string): void
    setVideoModelBaseUrlDraft(value: string): void
    setVideoModelModelIdDraft(value: string): void
    setCopywritingModelApiKeyDraft(value: string): void
    setCopywritingModelBaseUrlDraft(value: string): void
    setCopywritingModelModelIdDraft(value: string): void
    setDigitalHumanVolcAccessKeyDraft(value: string): void
    setDigitalHumanVolcSecretKeyDraft(value: string): void
    setDigitalHumanQiniuAccessKeyDraft(value: string): void
    setDigitalHumanQiniuSecretKeyDraft(value: string): void
    setVideoAnalyzerBaseUrlDraft(value: string): void
    setVideoAnalyzerModelIdDraft(value: string): void
    setVideoAnalyzerApiKeyDraft(value: string): void
    setReplicationBriefBaseUrlDraft(value: string): void
    setReplicationBriefModelIdDraft(value: string): void
    setReplicationBriefApiKeyDraft(value: string): void
    setVectcutBaseUrlDraft(value: string): void
    setVectcutFileBaseUrlDraft(value: string): void
    setVectcutApiKeyDraft(value: string): void
    setXhsFeishuAppIdDraft(value: string): void
    setXhsFeishuAppSecretDraft(value: string): void
    setXhsFeishuAppTokenDraft(value: string): void
    setXhsFeishuTableIdDraft(value: string): void
    setFeishuMobileAppIdDraft(value: string): void
    setFeishuMobileAppSecretDraft(value: string): void
  }
  labels: {
    saveSuccessPending: string
    saveSuccessApplied: string
    workspaceSaved: string
  }
  refresh(clearError?: boolean): Promise<WorkspaceSummary | null>
  normalizeError(value: unknown): string
}

export function useSaveSettings({
  config,
  desktopApi,
  saving,
  drafts,
  setters,
  labels,
  refresh,
  normalizeError
}: UseSaveSettingsOptions) {
  const saveConfig = useCallback(async (options?: {
    lobsterKey?: string
    workspacePath?: string
    expertModelConfig?: SaveConfigInput["expertModelConfig"]
    douyinRuntimeConfig?: SaveConfigInput["douyinRuntimeConfig"]
    xhsFeishuConfig?: SaveConfigInput["xhsFeishuConfig"]
    feishuMobileConfig?: SaveConfigInput["feishuMobileConfig"]
    successMessage?: string
    resetDrafts?: (savedConfig: AppConfig) => void
  }) => {
    if (!config || saving) {
      return false
    }

    const input: SaveConfigInput = {
      setupMode: config.setupMode,
      provider: config.provider,
      baseUrl: config.baseUrl,
      defaultModel: config.defaultModel,
      workspacePath: options?.workspacePath?.trim() || config.workspacePath,
      gatewayUrl: config.gatewayUrl,
      cloudApiBaseUrl: config.cloudApiBaseUrl,
      runtimeCloudApiBaseUrl: config.runtimeCloudApiBaseUrl.trim(),
      runtimeMode: "bundled-runtime"
    }

    const trimmedLobsterKey = options?.lobsterKey?.trim()
    if (typeof options?.lobsterKey === "string" && trimmedLobsterKey) {
      input.apiKey = trimmedLobsterKey
    }
    if (options?.expertModelConfig) {
      input.expertModelConfig = options.expertModelConfig
    }
    if (options?.douyinRuntimeConfig) {
      input.douyinRuntimeConfig = options.douyinRuntimeConfig
    }
    if (options?.xhsFeishuConfig) {
      input.xhsFeishuConfig = options.xhsFeishuConfig
    }
    if (options?.feishuMobileConfig) {
      input.feishuMobileConfig = options.feishuMobileConfig
    }

    setters.setSaving(true)
    setters.setErrorText("")
    setters.setInfoText("")

    try {
      const savedConfig = await desktopApi.config.save(input)
      setters.setConfig(savedConfig)
      options?.resetDrafts?.(savedConfig)
      setters.setInfoText(options?.successMessage ?? (trimmedLobsterKey ? labels.saveSuccessPending : labels.saveSuccessApplied))
      void refresh(false)
      return true
    } catch (error) {
      setters.setErrorText(normalizeError(error))
      return false
    } finally {
      setters.setSaving(false)
    }
  }, [config, desktopApi, labels.saveSuccessApplied, labels.saveSuccessPending, normalizeError, refresh, saving, setters])

  const saveLobsterKey = useCallback(async () => {
    return await saveConfig({
      lobsterKey: drafts.lobsterKey,
      resetDrafts: () => {
        setters.setLobsterKeyDraft("")
      }
    })
  }, [drafts.lobsterKey, saveConfig, setters])

  const pickWorkspaceDirectory = useCallback(async () => {
    if (!config || saving) {
      return
    }

    setters.setErrorText("")
    try {
      const nextPath = await desktopApi.config.pickWorkspaceDirectory(drafts.workspacePath.trim() || config.workspacePath)
      if (!nextPath?.trim()) {
        return
      }

      setters.setWorkspacePathDraft(nextPath.trim())
      setters.setInfoText("")
    } catch (error) {
      setters.setErrorText(normalizeError(error))
    }
  }, [config, desktopApi, drafts.workspacePath, normalizeError, saving, setters])

  const restoreWorkspaceDirectory = useCallback(() => {
    if (!config) {
      return
    }

    setters.setWorkspacePathDraft(config.workspacePath)
    setters.setErrorText("")
    setters.setInfoText("")
  }, [config, setters])

  const saveWorkspaceDirectory = useCallback(async () => {
    return await saveConfig({
      workspacePath: drafts.workspacePath,
      successMessage: labels.workspaceSaved,
      resetDrafts: (savedConfig) => {
        setters.setWorkspacePathDraft(savedConfig.workspacePath)
      }
    })
  }, [drafts.workspacePath, labels.workspaceSaved, saveConfig, setters])

  const saveXhsFeishuConfig = useCallback(async () => {
    return await saveConfig({
      xhsFeishuConfig: {
        appId: drafts.xhsFeishuAppId.trim() || undefined,
        appSecret: drafts.xhsFeishuAppSecret.trim() || undefined,
        appToken: drafts.xhsFeishuAppToken.trim() || undefined,
        tableId: drafts.xhsFeishuTableId.trim() || undefined
      },
      resetDrafts: () => {
        setters.setXhsFeishuAppIdDraft("")
        setters.setXhsFeishuAppSecretDraft("")
        setters.setXhsFeishuAppTokenDraft("")
        setters.setXhsFeishuTableIdDraft("")
      }
    })
  }, [drafts.xhsFeishuAppId, drafts.xhsFeishuAppSecret, drafts.xhsFeishuAppToken, drafts.xhsFeishuTableId, saveConfig, setters])

  const saveFeishuMobileConfig = useCallback(async () => {
    return await saveConfig({
      feishuMobileConfig: {
        appId: drafts.feishuMobileAppId.trim() || undefined,
        appSecret: drafts.feishuMobileAppSecret.trim() || undefined
      },
      resetDrafts: () => {
        setters.setFeishuMobileAppIdDraft("")
        setters.setFeishuMobileAppSecretDraft("")
      }
    })
  }, [drafts.feishuMobileAppId, drafts.feishuMobileAppSecret, saveConfig, setters])

  const saveCopywritingConfig = useCallback(async () => {
    return await saveConfig({
      expertModelConfig: {
        copywriting: {
          baseUrl: drafts.copywritingModelBaseUrl.trim() || undefined,
          modelId: drafts.copywritingModelModelId.trim() || undefined,
          apiKey: drafts.copywritingModelApiKey.trim() || undefined
        }
      },
      resetDrafts: (savedConfig) => {
        setters.setCopywritingModelApiKeyDraft("")
        setters.setCopywritingModelBaseUrlDraft(savedConfig.expertModelConfig.copywriting.baseUrl)
        setters.setCopywritingModelModelIdDraft(savedConfig.expertModelConfig.copywriting.modelId ?? "")
      }
    })
  }, [drafts.copywritingModelApiKey, drafts.copywritingModelBaseUrl, drafts.copywritingModelModelId, saveConfig, setters])

  const saveImageConfig = useCallback(async () => {
    return await saveConfig({
      expertModelConfig: {
        image: {
          baseUrl: drafts.imageModelBaseUrl.trim() || undefined,
          modelId: drafts.imageModelModelId.trim() || undefined,
          apiKey: drafts.imageModelApiKey.trim() || undefined
        }
      },
      resetDrafts: (savedConfig) => {
        setters.setImageModelApiKeyDraft("")
        setters.setImageModelBaseUrlDraft(savedConfig.expertModelConfig.image.baseUrl)
        setters.setImageModelModelIdDraft(savedConfig.expertModelConfig.image.modelId ?? "")
      }
    })
  }, [drafts.imageModelApiKey, drafts.imageModelBaseUrl, drafts.imageModelModelId, saveConfig, setters])

  const saveVideoConfig = useCallback(async () => {
    return await saveConfig({
      expertModelConfig: {
        video: {
          baseUrl: drafts.videoModelBaseUrl.trim() || undefined,
          modelId: drafts.videoModelModelId.trim() || undefined,
          apiKey: drafts.videoModelApiKey.trim() || undefined
        }
      },
      resetDrafts: (savedConfig) => {
        setters.setVideoModelApiKeyDraft("")
        setters.setVideoModelBaseUrlDraft(savedConfig.expertModelConfig.video.baseUrl)
        setters.setVideoModelModelIdDraft(savedConfig.expertModelConfig.video.modelId ?? "")
      }
    })
  }, [drafts.videoModelApiKey, drafts.videoModelBaseUrl, drafts.videoModelModelId, saveConfig, setters])

  const saveDigitalHumanConfig = useCallback(async () => {
    return await saveConfig({
      expertModelConfig: {
        digitalHuman: {
          volcAccessKey: drafts.digitalHumanVolcAccessKey.trim() || undefined,
          volcSecretKey: drafts.digitalHumanVolcSecretKey.trim() || undefined,
          qiniuAccessKey: drafts.digitalHumanQiniuAccessKey.trim() || undefined,
          qiniuSecretKey: drafts.digitalHumanQiniuSecretKey.trim() || undefined
        }
      },
      resetDrafts: () => {
        setters.setDigitalHumanVolcAccessKeyDraft("")
        setters.setDigitalHumanVolcSecretKeyDraft("")
        setters.setDigitalHumanQiniuAccessKeyDraft("")
        setters.setDigitalHumanQiniuSecretKeyDraft("")
      }
    })
  }, [drafts.digitalHumanQiniuAccessKey, drafts.digitalHumanQiniuSecretKey, drafts.digitalHumanVolcAccessKey, drafts.digitalHumanVolcSecretKey, saveConfig, setters])

  const saveDouyinRuntimeConfig = useCallback(async () => {
    return await saveConfig({
      douyinRuntimeConfig: {
        videoAnalyzer: {
          baseUrl: drafts.videoAnalyzerBaseUrl.trim() || undefined,
          modelId: drafts.videoAnalyzerModelId.trim() || undefined,
          apiKey: drafts.videoAnalyzerApiKey.trim() || undefined
        },
        replicationBrief: {
          baseUrl: drafts.replicationBriefBaseUrl.trim() || undefined,
          modelId: drafts.replicationBriefModelId.trim() || undefined,
          apiKey: drafts.replicationBriefApiKey.trim() || undefined
        },
        vectcut: {
          baseUrl: drafts.vectcutBaseUrl.trim() || undefined,
          fileBaseUrl: drafts.vectcutFileBaseUrl.trim() || undefined,
          apiKey: drafts.vectcutApiKey.trim() || undefined
        }
      },
      resetDrafts: (savedConfig) => {
        setters.setVideoAnalyzerBaseUrlDraft(savedConfig.douyinRuntimeConfig.videoAnalyzer.baseUrl)
        setters.setVideoAnalyzerModelIdDraft(savedConfig.douyinRuntimeConfig.videoAnalyzer.modelId ?? "")
        setters.setVideoAnalyzerApiKeyDraft("")
        setters.setReplicationBriefBaseUrlDraft(savedConfig.douyinRuntimeConfig.replicationBrief.baseUrl)
        setters.setReplicationBriefModelIdDraft(savedConfig.douyinRuntimeConfig.replicationBrief.modelId ?? "")
        setters.setReplicationBriefApiKeyDraft("")
        setters.setVectcutBaseUrlDraft(savedConfig.douyinRuntimeConfig.vectcut.baseUrl)
        setters.setVectcutFileBaseUrlDraft(savedConfig.douyinRuntimeConfig.vectcut.fileBaseUrl)
        setters.setVectcutApiKeyDraft("")
      }
    })
  }, [
    drafts.replicationBriefApiKey,
    drafts.replicationBriefBaseUrl,
    drafts.replicationBriefModelId,
    drafts.vectcutApiKey,
    drafts.vectcutBaseUrl,
    drafts.vectcutFileBaseUrl,
    drafts.videoAnalyzerApiKey,
    drafts.videoAnalyzerBaseUrl,
    drafts.videoAnalyzerModelId,
    saveConfig,
    setters
  ])

  return {
    saveConfig,
    saveLobsterKey,
    saveWorkspaceDirectory,
    restoreWorkspaceDirectory,
    saveXhsFeishuConfig,
    saveFeishuMobileConfig,
    saveCopywritingConfig,
    saveImageConfig,
    saveVideoConfig,
    saveDigitalHumanConfig,
    saveDouyinRuntimeConfig,
    pickWorkspaceDirectory
  }
}
