import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { agentApi, databaseApi, mcpApi, skillApi } from '@/apis'
import { isDefaultAllAgentResourceKind } from '@/utils/agentConfigUtils'
import { handleChatError } from '@/utils/errorHandler'

function normalizeAgent(agent) {
  const agentId = agent?.agent_id || agent?.slug || agent?.id
  return agentId
    ? { ...agent, id: agentId, agent_id: agentId, slug: agent?.slug || agentId }
    : agent
}

export const BUILTIN_AGENT_ID = 'default-chatbot'

export function isBuiltinAgent(agent) {
  return agent?.is_builtin || agent?.id === BUILTIN_AGENT_ID || agent?.slug === BUILTIN_AGENT_ID
}

function sortAgents(agents) {
  return [...agents].sort((a, b) => {
    if (isBuiltinAgent(a) !== isBuiltinAgent(b)) return isBuiltinAgent(a) ? -1 : 1
    return String(a.name || a.id).localeCompare(String(b.name || b.id), 'zh-CN')
  })
}

function getPreferredAgentId(agents, persistedId) {
  const chatAgents = agents.filter((agent) => !agent.is_subagent)
  if (persistedId && chatAgents.some((agent) => agent.id === persistedId)) return persistedId
  return chatAgents.find(isBuiltinAgent)?.id || chatAgents[0]?.id || null
}

function extractContext(agent) {
  const configJson = agent?.config_json || {}
  return { ...(configJson.context || configJson || {}) }
}

export const useAgentStore = defineStore(
  'agent',
  () => {
    const agents = ref([])
    const selectedAgentId = ref(null)

    const availableKnowledgeBases = ref([])
    const availableMcps = ref([])
    const availableSkills = ref([])

    const agentConfig = ref({})
    const originalAgentConfig = ref({})
    const agentDetails = ref({})

    const isLoadingAgents = ref(false)
    const isLoadingConfig = ref(false)
    const isLoadingAgentDetail = ref(false)
    const error = ref(null)
    const isInitialized = ref(false)
    const isInitializing = ref(false)

    const selectedAgent = computed(() => {
      const agentId = selectedAgentId.value
      return agentId
        ? agentDetails.value[agentId] || agents.value.find((a) => a.id === agentId) || null
        : null
    })

    const agentsList = computed(() => agents.value)

    const configurableItems = computed(() => {
      const items = { ...(selectedAgent.value?.configurable_items || {}) }
      Object.keys(items).forEach((key) => {
        const item = items[key]
        if (item?.x_oap_ui_config) {
          items[key] = { ...item, ...item.x_oap_ui_config }
          delete items[key].x_oap_ui_config
        }
      })
      return items
    })

    const availableTools = computed(() => configurableItems.value.tools?.options || [])
    const hasConfigChanges = computed(
      () => JSON.stringify(agentConfig.value) !== JSON.stringify(originalAgentConfig.value)
    )

    async function fetchMentionResources() {
      try {
        const [dbsRes, mcpsRes, skillsRes] = await Promise.all([
          databaseApi.getAccessibleDatabases().catch(() => ({ databases: [] })),
          mcpApi.getMcpServers().catch(() => ({ data: [] })),
          skillApi.listAccessibleSkills().catch(() => ({ data: [] }))
        ])
        availableKnowledgeBases.value = dbsRes.databases || []
        availableMcps.value = mcpsRes.data || []
        availableSkills.value = skillsRes.data || []
      } catch (e) {
        console.warn('Failed to fetch mention resources:', e)
      }
    }

    async function initialize() {
      if (isInitialized.value || isInitializing.value) return
      isInitializing.value = true
      try {
        await Promise.all([fetchAgents(), fetchMentionResources()])

        const targetAgentId = getPreferredAgentId(agents.value, selectedAgentId.value)
        if (targetAgentId) {
          await selectAgent(targetAgentId)
        }
        isInitialized.value = true
      } catch (err) {
        console.error('Failed to initialize agent store:', err)
        handleChatError(err, 'initialize')
        error.value = err.message
      } finally {
        isInitializing.value = false
      }
    }

    async function fetchAgents({ includeSubagents = false } = {}) {
      isLoadingAgents.value = true
      error.value = null
      try {
        const response = await agentApi.getAgents({ includeSubagents })
        agents.value = sortAgents((response.agents || []).map(normalizeAgent))
      } catch (err) {
        console.error('Failed to fetch agents:', err)
        handleChatError(err, 'fetch')
        error.value = err.message
        throw err
      } finally {
        isLoadingAgents.value = false
      }
    }

    function applyConfigDefaults(loadedConfig, configItems = configurableItems.value) {
      const items = { ...configItems }
      Object.keys(items).forEach((key) => {
        const item = items[key]?.x_oap_ui_config
          ? { ...items[key], ...items[key].x_oap_ui_config }
          : items[key]
        const isDefaultAllList = isDefaultAllAgentResourceKind(item?.kind)
        if (loadedConfig[key] === undefined || (loadedConfig[key] === null && !isDefaultAllList)) {
          if (item.default !== undefined) loadedConfig[key] = item.default
        }
        if (
          loadedConfig[key] !== undefined &&
          loadedConfig[key] !== null &&
          loadedConfig[key] !== '' &&
          (item?.type === 'number' || item?.type === 'int' || item?.type === 'float')
        ) {
          const numericValue = Number(loadedConfig[key])
          if (!Number.isNaN(numericValue)) {
            loadedConfig[key] = item.type === 'int' ? Math.trunc(numericValue) : numericValue
          }
        }
      })
      return loadedConfig
    }

    async function fetchAgentDetail(agentId, forceRefresh = false) {
      if (!agentId) return null
      if (!forceRefresh && agentDetails.value[agentId]) return agentDetails.value[agentId]

      isLoadingAgentDetail.value = true
      error.value = null
      try {
        const response = await agentApi.getAgentDetail(agentId)
        const agent = normalizeAgent(response.agent || response)
        agentDetails.value[agent.id] = agent
        return agent
      } catch (err) {
        console.error(`Failed to fetch agent detail for ${agentId}:`, err)
        handleChatError(err, 'fetch')
        error.value = err.message
        throw err
      } finally {
        isLoadingAgentDetail.value = false
      }
    }

    async function selectAgent(agentId, { allowSubagent = false } = {}) {
      if (!agentId) return
      let knownAgent = agentDetails.value[agentId] || agents.value.find((a) => a.id === agentId)
      if (!knownAgent) {
        knownAgent = await fetchAgentDetail(agentId)
      }
      if (knownAgent?.is_subagent && !allowSubagent) return
      isLoadingConfig.value = true
      try {
        const detail = agentDetails.value[agentId] || (await fetchAgentDetail(agentId))
        const loadedConfig = applyConfigDefaults(
          extractContext(detail),
          detail?.configurable_items || {}
        )
        selectedAgentId.value = agentId
        agentConfig.value = loadedConfig
        originalAgentConfig.value = { ...loadedConfig }
      } finally {
        isLoadingConfig.value = false
      }
    }

    async function saveAgentConfig() {
      const targetAgentId = selectedAgentId.value
      if (!targetAgentId) return
      try {
        const response = await agentApi.updateAgent(targetAgentId, {
          config_json: { context: agentConfig.value }
        })
        const updated = normalizeAgent(response.agent)
        agentDetails.value[targetAgentId] = updated
        const index = agents.value.findIndex((item) => item.id === targetAgentId)
        if (index >= 0) agents.value.splice(index, 1, updated)
        originalAgentConfig.value = { ...agentConfig.value }
      } catch (err) {
        console.error('Failed to save agent config:', err)
        handleChatError(err, 'save')
        error.value = err.message
        throw err
      }
    }

    async function createAgent(payload) {
      const response = await agentApi.createAgent(payload)
      const created = normalizeAgent(response.agent)
      if (created?.id) {
        agentDetails.value[created.id] = created
        agents.value = sortAgents([
          created,
          ...agents.value.filter((item) => item.id !== created.id)
        ])
        if (!created.is_subagent) await selectAgent(created.id)
      }
      return created
    }

    async function updateAgentProfile(agentId, payload) {
      const response = await agentApi.updateAgent(agentId, payload)
      const updated = normalizeAgent(response.agent)
      agentDetails.value[updated.id] = updated
      const index = agents.value.findIndex((item) => item.id === updated.id)
      if (index >= 0) agents.value.splice(index, 1, updated)
      return updated
    }

    async function deleteAgent(agentId) {
      await agentApi.deleteAgent(agentId)
      agents.value = agents.value.filter((item) => item.id !== agentId)
      delete agentDetails.value[agentId]
      if (selectedAgentId.value === agentId) {
        selectedAgentId.value = null
        agentConfig.value = {}
        originalAgentConfig.value = {}
        const nextAgentId = getPreferredAgentId(agents.value)
        if (nextAgentId) await selectAgent(nextAgentId)
      }
    }

    function resetAgentConfig() {
      agentConfig.value = { ...originalAgentConfig.value }
    }

    function updateAgentConfig(updates) {
      Object.assign(agentConfig.value, updates)
    }

    function reset() {
      agents.value = []
      selectedAgentId.value = null
      availableKnowledgeBases.value = []
      availableMcps.value = []
      availableSkills.value = []
      agentConfig.value = {}
      originalAgentConfig.value = {}
      agentDetails.value = {}
      isLoadingAgents.value = false
      isLoadingConfig.value = false
      isLoadingAgentDetail.value = false
      error.value = null
      isInitialized.value = false
      isInitializing.value = false
    }

    return {
      agents,
      selectedAgentId,
      availableKnowledgeBases,
      availableMcps,
      availableSkills,
      agentConfig,
      originalAgentConfig,
      agentDetails,
      isLoadingAgents,
      isLoadingConfig,
      isLoadingAgentDetail,
      error,
      isInitialized,
      selectedAgent,
      agentsList,
      configurableItems,
      availableTools,
      hasConfigChanges,
      initialize,
      fetchAgents,
      fetchAgentDetail,
      fetchMentionResources,
      selectAgent,
      saveAgentConfig,
      createAgent,
      updateAgentProfile,
      deleteAgent,
      resetAgentConfig,
      updateAgentConfig,
      reset
    }
  },
  {
    persist: {
      key: 'agent-store',
      storage: localStorage,
      pick: ['selectedAgentId']
    }
  }
)
