import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { API } from '@/Api'
import type { AdminConfig, PromptsLibrary } from '@/types/admin-config'
import { usePrefStore } from '@/store/prefStore'
import { useToolsStore } from '@/store/toolsStore'
import { useAgentCatalogStore } from '@/store/agentCatalogStore'
import { usePromptStore } from '@/store/promptStore'
import { getSocketId } from '@/composables/useSocket'

type WithMeta<T> = T & { _meta?: { etag?: string } }

function deepClone<T>(v: T): T {
  return JSON.parse(JSON.stringify(v))
}

export const useAdminConfigStore = defineStore('adminConfig', () => {
  const original = ref<WithMeta<AdminConfig> | undefined>(undefined)
  const draft = ref<WithMeta<AdminConfig> | undefined>(undefined)

  const originalLibrary = ref<WithMeta<PromptsLibrary> | undefined>(undefined)
  const draftLibrary = ref<WithMeta<PromptsLibrary> | undefined>(undefined)

  const loaded = ref(false)
  const loading = ref(false)
  const savingConfig = ref(false)
  const savingLibrary = ref(false)
  const error = ref<string | null>(null)

  const dirty = computed(
    () =>
      JSON.stringify(original.value?.promptsAttributesById ?? {}) !==
        JSON.stringify(draft.value?.promptsAttributesById ?? {}) ||
      JSON.stringify({
        ...(original.value ?? {}),
        promptsAttributesById: undefined,
        _meta: undefined,
      }) !==
        JSON.stringify({
          ...(draft.value ?? {}),
          promptsAttributesById: undefined,
          _meta: undefined,
        })
  )

  const dirtyLibrary = computed(
    () =>
      JSON.stringify({ ...(originalLibrary.value ?? {}), _meta: undefined }) !==
      JSON.stringify({ ...(draftLibrary.value ?? {}), _meta: undefined })
  )

  const sectionDirty = (section: string) => {
    if (!loaded.value || !original.value || !draft.value) return false
    const sectionKey = section === 'prompts' ? 'promptsAttributesById' : section
    return (
      JSON.stringify((original.value as any)[sectionKey]) !==
      JSON.stringify((draft.value as any)[sectionKey])
    )
  }

  const isSectionDirty = (sectionId: string): boolean => {
    switch (sectionId) {
      case 'system':
        return (
          sectionDirty('agentHubLLM') ||
          sectionDirty('agentHubOptionalInstructions') ||
          sectionDirty('orchestrationMode') ||
          sectionDirty('logsLevel') ||
          sectionDirty('permanentlyDeleteMessages')
        )
      case 'enterprise-agents':
        return sectionDirty('enterpriseAgents')
      case 'my-agents':
        return (
          sectionDirty('myAgentsEnabled') ||
          sectionDirty('myAgentsTextCompletionModels') ||
          sectionDirty('myAgentsEmbeddingModel') ||
          sectionDirty('myAgentsFsConnection') ||
          sectionDirty('myAgentsFolder') ||
          sectionDirty('myAgentsNumDocs') ||
          sectionDirty('myAgentsManagedTools') ||
          sectionDirty('myAgentsEnablePromptLibrary') ||
          sectionDirty('myAgentsEnableGroupsRestriction') ||
          sectionDirty('myAgentsExcludedShareGroups')
        )
      case 'charts':
        return (
          sectionDirty('chartsGenerationMode') ||
          sectionDirty('chartsTextCompletionModel') ||
          sectionDirty('chartsMaxArtifactsSize')
        )
      case 'prompts':
        return sectionDirty('promptsAttributesById')
      case 'conversation-files':
        return (
          sectionDirty('enableDocumentUpload') ||
          sectionDirty('extractionMode') ||
          sectionDirty('textExtractionType') ||
          sectionDirty('maxImagesInConversation') ||
          sectionDirty('uploadManagedFolder') ||
          sectionDirty('conversationVisionLLM')
        )
      case 'user-experience':
        return (
          sectionDirty('smartMode') ||
          sectionDirty('allowDisableAgents') ||
          sectionDirty('conversationStarterExamples')
        )
      default:
        return false
    }
  }

  const saving = computed(() => savingConfig.value || savingLibrary.value)

  async function load() {
    loading.value = true
    error.value = null
    try {
      const [cfg, lib] = await Promise.all([API.getAdminConfig(), API.getPromptsLibrary()])
      original.value = cfg.data
      draft.value = deepClone(cfg.data)
      originalLibrary.value = lib.data
      draftLibrary.value = deepClone(lib.data)
      loaded.value = true
    } catch (e: any) {
      error.value = e?.message || 'Failed to load config'
      console.error('Error loading admin config / prompts library:', e)
    } finally {
      loading.value = false
    }
  }

  async function reloadAdminAffectedStores() {
    // Reload stores that depend on admin config settings
    const prefStore = usePrefStore()
    const toolsStore = useToolsStore()
    const agentCatalog = useAgentCatalogStore()
    const promptStore = usePromptStore()

    // Reset prompt store to force reload (since loadTemplates has a guard)
    promptStore.reset()

    await Promise.all([
      prefStore.reload(),
      toolsStore.refresh(),
      agentCatalog.load(true),
      promptStore.loadTemplates(),
    ])
  }

  async function save() {
    if (!draft.value) return false
    savingConfig.value = true
    error.value = null
    try {
      const etag = original.value?._meta?.etag
      const socketId = getSocketId()
      await API.saveAdminConfig({
        config: draft.value as AdminConfig,
        etag,
        socketId: socketId || undefined,
      })
      const cfg = await API.getAdminConfig()
      original.value = cfg.data
      draft.value = deepClone(cfg.data)

      await reloadAdminAffectedStores()

      return true
    } catch (e: any) {
      error.value = e?.message || 'Failed to save admin config'
      console.error('Error saving admin config:', e)
      return false
    } finally {
      savingConfig.value = false
    }
  }

  async function saveLibrary() {
    if (!draftLibrary.value) return false
    savingLibrary.value = true
    error.value = null
    try {
      const promptsEtag = originalLibrary.value?._meta?.etag
      const { version, prompts } = draftLibrary.value
      const socketId = getSocketId()
      await API.savePromptsLibrary({
        data: { version, prompts },
        etag: promptsEtag,
        socketId: socketId || undefined,
      })
      const lib = await API.getPromptsLibrary()
      originalLibrary.value = lib.data
      draftLibrary.value = deepClone(lib.data)

      // Reload user prompt store templates after library update
      const promptStore = usePromptStore()
      promptStore.reset()
      await promptStore.loadTemplates()

      return true
    } catch (e: any) {
      error.value = e?.message || 'Failed to save prompts library'
      console.error('Error saving prompts library:', e)
      return false
    } finally {
      savingLibrary.value = false
    }
  }

  function isPromptEnabled(id: string): boolean {
    const attrs = draft.value?.promptsAttributesById ?? {}
    const override = (attrs as Record<string, { enabled?: boolean }>)[id]
    return override?.enabled !== false
  }

  function setPromptEnabled(id: string, enabled: boolean) {
    if (!draft.value) return
    const byId = (draft.value.promptsAttributesById ||= {})
    if (enabled) {
      delete (byId as Record<string, any>)[id]
    } else {
      ;(byId as Record<string, any>)[id] = { enabled: false }
    }
  }

  function discard() {
    if (original.value) {
      draft.value = deepClone(original.value)
    }
  }

  function reset() {
    original.value = undefined
    draft.value = undefined
    originalLibrary.value = undefined
    draftLibrary.value = undefined
    loaded.value = false
    loading.value = false
    savingLibrary.value = false
    savingConfig.value = false
    error.value = null
  }

  return {
    original,
    draft,
    originalLibrary,
    draftLibrary,
    loaded,
    loading,
    savingConfig,
    savingLibrary,
    error,

    dirty,
    dirtyLibrary,
    sectionDirty,
    isSectionDirty,
    saving,

    load,
    save,
    saveLibrary,
    reloadAdminAffectedStores,
    discard,
    reset,

    isPromptEnabled,
    setPromptEnabled,
  }
})
