import { useContext, useEffect, useMemo, useState } from 'react'
import { Descriptions, Flex, Select, Space, Spin, Typography } from 'antd'
import { LoadingOutlined, SettingOutlined } from '@ant-design/icons'
import { useThemeContext } from '../context/ThemeContext'
import { ApiServerContext } from '../context/ApiServerContext'
import { ElectronContext } from '../context/ElectronContext'
import { AuthContext } from '../context/AuthContext'
import {
  normalizeAppUpdateEngine,
  useAppUpdateContext
} from '../context/AppUpdateContext'
import { useMessageContext } from '../context/MessageContext'
import useCollapseState from '../hooks/useCollapseState'
import InfoCollapse from '../common/InfoCollapse'
import ViewButton from '../common/ViewButton'
import EditButtons from '../common/EditButtons'

const { Text } = Typography
const { Option } = Select
const DEFAULT_UPDATE_BRANCH = 'main'
const DEFAULT_UPDATE_ENGINE = 'native'

const engineLabel = (engine) => {
  const normalized = normalizeAppUpdateEngine(engine)
  if (normalized === 'chromium') return 'Chromium'
  if (normalized === 'native') return 'Native'
  return 'Not configured'
}

const Settings = () => {
  const { isDarkMode, isCompact, isSystem, setThemeMode, setDensityMode } =
    useThemeContext()
  const { fetchAppUpdateBranches } = useContext(ApiServerContext)
  const { isElectron, getAppSettings, setAppSettings, getAppEngine } =
    useContext(ElectronContext)
  const { recheckForUpdates } = useAppUpdateContext()
  const { userProfile, setUserProfile } = useContext(AuthContext)
  const { showSuccess, showError } = useMessageContext()
  const [collapseState, updateCollapseState] = useCollapseState('Settings', {
    appearance: true,
    appUpdates: true
  })
  const [isEditing, setIsEditing] = useState(false)
  const [settingsLoading, setSettingsLoading] = useState(true)
  const [saving, setSaving] = useState(false)
  const [appSettings, setAppSettingsState] = useState({})
  const [draftSettings, setDraftSettings] = useState({})
  const [branches, setBranches] = useState([])
  const [branchLoading, setBranchLoading] = useState(false)
  const [runningEngine, setRunningEngine] = useState(DEFAULT_UPDATE_ENGINE)

  useEffect(() => {
    const loadSettings = async () => {
      setSettingsLoading(true)
      const [storedSettings, detectedEngine] = await Promise.all([
        isElectron ? getAppSettings() : Promise.resolve(userProfile?.settings || {}),
        isElectron ? getAppEngine() : Promise.resolve(DEFAULT_UPDATE_ENGINE)
      ])
      const nextEngine =
        normalizeAppUpdateEngine(detectedEngine) || DEFAULT_UPDATE_ENGINE
      setRunningEngine(nextEngine)

      const nextSettings = { ...(storedSettings || {}) }
      if (isElectron && !normalizeAppUpdateEngine(nextSettings.appUpdateEngine)) {
        nextSettings.appUpdateEngine = nextEngine
      }

      setAppSettingsState(nextSettings)
      setDraftSettings(nextSettings)
      setSettingsLoading(false)
    }

    loadSettings()
  }, [getAppEngine, getAppSettings, isElectron, userProfile?.settings])

  useEffect(() => {
    if (settingsLoading || isEditing) return
    if (appSettings.theme) setThemeMode(appSettings.theme)
    if (appSettings.density) setDensityMode(appSettings.density)
  }, [
    appSettings.density,
    appSettings.theme,
    isEditing,
    setDensityMode,
    setThemeMode,
    settingsLoading
  ])

  useEffect(() => {
    if (!isElectron) {
      setBranches([])
      setBranchLoading(false)
      return
    }

    const loadBranches = async () => {
      setBranchLoading(true)
      const availableBranches = await fetchAppUpdateBranches()
      setBranches(availableBranches)

      setDraftSettings((previous) => {
        if (previous.appUpdateBranch) return previous

        const defaultBranch = availableBranches.includes(DEFAULT_UPDATE_BRANCH)
          ? DEFAULT_UPDATE_BRANCH
          : availableBranches[0]

        return defaultBranch
          ? { ...previous, appUpdateBranch: defaultBranch }
          : previous
      })

      setBranchLoading(false)
    }

    loadBranches()
  }, [fetchAppUpdateBranches, isElectron])

  const branchOptions = useMemo(
    () =>
      branches.map((branch) => (
        <Option key={branch} value={branch}>
          {branch}
        </Option>
      )),
    [branches]
  )
  const viewItems = [
    { key: 'appearance', label: 'Appearance Settings' },
    ...(isElectron ? [{ key: 'appUpdates', label: 'App Update Settings' }] : [])
  ]

  const getCurrentThemeValue = () => {
    if (isSystem) return 'system'
    return isDarkMode ? 'dark' : 'light'
  }

  const currentThemeValue = getCurrentThemeValue()
  const currentDensityValue = isCompact ? 'compact' : 'comfortable'
  const currentBranch =
    appSettings.appUpdateBranch ||
    (branches.includes(DEFAULT_UPDATE_BRANCH) ? DEFAULT_UPDATE_BRANCH : null) ||
    branches[0] ||
    'Not configured'
  const currentEngine =
    normalizeAppUpdateEngine(appSettings.appUpdateEngine) ||
    normalizeAppUpdateEngine(runningEngine) ||
    DEFAULT_UPDATE_ENGINE

  const startEditing = () => {
    setDraftSettings({
      ...appSettings,
      appUpdateBranch:
        currentBranch === 'Not configured' ? undefined : currentBranch,
      appUpdateEngine: currentEngine,
      theme: currentThemeValue,
      density: currentDensityValue
    })
    setIsEditing(true)
  }

  const cancelEditing = () => {
    setDraftSettings(appSettings)
    setIsEditing(false)
  }

  const handleSave = async () => {
    setSaving(true)

    try {
      const nextEngine =
        normalizeAppUpdateEngine(draftSettings.appUpdateEngine) ||
        currentEngine
      const nextSettings = {
        ...appSettings,
        theme: draftSettings.theme,
        density: draftSettings.density,
        ...(isElectron
          ? {
              appUpdateBranch: draftSettings.appUpdateBranch,
              appUpdateEngine: nextEngine
            }
          : {})
      }
      const saved = isElectron
        ? await setAppSettings(nextSettings)
        : Boolean(userProfile)

      if (!saved) {
        showError('Unable to save settings.')
        return
      }

      if (!isElectron) {
        setUserProfile((previous) => ({
          ...previous,
          settings: {
            ...(previous?.settings || {}),
            theme: draftSettings.theme,
            density: draftSettings.density
          }
        }))
      }

      setThemeMode(draftSettings.theme)
      setDensityMode(draftSettings.density)
      setAppSettingsState(nextSettings)
      setDraftSettings(nextSettings)
      setIsEditing(false)
      showSuccess('Settings saved.')

      const appUpdateSettingsChanged =
        isElectron &&
        (nextSettings.appUpdateBranch !== appSettings.appUpdateBranch ||
          nextSettings.appUpdateEngine !==
            normalizeAppUpdateEngine(appSettings.appUpdateEngine))

      if (appUpdateSettingsChanged) {
        void recheckForUpdates()
      }
    } finally {
      setSaving(false)
    }
  }

  return (
    <Flex vertical gap='large' style={{ height: '100%', minHeight: 0 }}>
      <Flex justify='space-between' align='center'>
        <Space size='small'>
          <ViewButton
            disabled={settingsLoading}
            items={viewItems}
            visibleState={collapseState}
            updateVisibleState={updateCollapseState}
          />
        </Space>
        <EditButtons
          isEditing={isEditing}
          handleUpdate={handleSave}
          cancelEditing={cancelEditing}
          startEditing={startEditing}
          formValid={
            Boolean(draftSettings.theme && draftSettings.density) &&
            (!isElectron ||
              (Boolean(draftSettings.appUpdateBranch) &&
                Boolean(normalizeAppUpdateEngine(draftSettings.appUpdateEngine))))
          }
          disabled={settingsLoading || (!isElectron && !userProfile)}
          loading={saving}
        />
      </Flex>
      <div style={{ height: '100%', minHeight: 0, overflowY: 'auto' }}>
        <Spin spinning={settingsLoading} indicator={<LoadingOutlined />}>
          <Flex vertical gap='large'>
            <InfoCollapse
              title='Appearance Settings'
              icon={<SettingOutlined />}
              active={collapseState.appearance}
              onToggle={(expanded) =>
                updateCollapseState('appearance', expanded)
              }
              collapseKey='appearance'
            >
              <Descriptions
                bordered
                column={{
                  xs: 1,
                  sm: 1,
                  md: 1,
                  lg: 2,
                  xl: 2,
                  xxl: 2
                }}
              >
                <Descriptions.Item label='Theme'>
                  {isEditing ? (
                    <Select
                      value={draftSettings.theme}
                      onChange={(value) =>
                        setDraftSettings((previous) => ({
                          ...previous,
                          theme: value
                        }))
                      }
                      style={{ width: '100%' }}
                    >
                      <Option value='light'>Light</Option>
                      <Option value='dark'>Dark</Option>
                      <Option value='system'>System</Option>
                    </Select>
                  ) : (
                    <Text>{currentThemeValue}</Text>
                  )}
                </Descriptions.Item>
                <Descriptions.Item label='UI Density'>
                  {isEditing ? (
                    <Select
                      value={draftSettings.density}
                      onChange={(value) =>
                        setDraftSettings((previous) => ({
                          ...previous,
                          density: value
                        }))
                      }
                      style={{ width: '100%' }}
                    >
                      <Option value='comfortable'>Comfortable</Option>
                      <Option value='compact'>Compact</Option>
                    </Select>
                  ) : (
                    <Text>{isCompact ? 'Compact' : 'Comfortable'}</Text>
                  )}
                </Descriptions.Item>
              </Descriptions>
            </InfoCollapse>
            {isElectron && (
              <InfoCollapse
                title='App Update Settings'
                icon={<SettingOutlined />}
                active={collapseState.appUpdates}
                onToggle={(expanded) =>
                  updateCollapseState('appUpdates', expanded)
                }
                collapseKey='appUpdates'
              >
                <Descriptions bordered column={1}>
                  <Descriptions.Item label='Branch'>
                    {isEditing ? (
                      <Select
                        value={draftSettings.appUpdateBranch}
                        onChange={(value) =>
                          setDraftSettings((previous) => ({
                            ...previous,
                            appUpdateBranch: value
                          }))
                        }
                        style={{ width: '100%' }}
                        loading={branchLoading}
                        placeholder='Select a branch'
                      >
                        {branchOptions}
                      </Select>
                    ) : (
                      <Text>{currentBranch}</Text>
                    )}
                  </Descriptions.Item>
                  <Descriptions.Item label='Engine'>
                    {isEditing ? (
                      <Select
                        value={
                          normalizeAppUpdateEngine(draftSettings.appUpdateEngine) ||
                          currentEngine
                        }
                        onChange={(value) =>
                          setDraftSettings((previous) => ({
                            ...previous,
                            appUpdateEngine: value
                          }))
                        }
                        style={{ width: '100%' }}
                        placeholder='Select an engine'
                      >
                        <Option value='native'>Native</Option>
                        <Option value='chromium'>Chromium</Option>
                      </Select>
                    ) : (
                      <Text>{engineLabel(currentEngine)}</Text>
                    )}
                  </Descriptions.Item>
                </Descriptions>
              </InfoCollapse>
            )}
          </Flex>
        </Spin>
      </div>
    </Flex>
  )
}

export default Settings
