import { useEffect, useMemo, useRef, useState } from 'react'
import {
  ACTION_LABELS,
  INPUT_ACTIONS,
  useInput,
  useGameAction,
  type InputAction,
  type InputDevice,
} from '../input'
import {
  ControllerBindingLabel,
  ControllerStylePreview,
} from './ControllerIcons'
import { useDualScreen } from '../dualScreen'
import {
  getNativeDisplays,
  hasNativeDualScreenBridge,
  type AndroidDisplay,
} from '../nativeDualScreen'

type SettingsTab = 'display' | 'input' | 'bindings'

type SettingsNavEntry =
  | { kind: 'back'; key: string; row: number; column: number }
  | { kind: 'tab'; key: string; row: number; column: number; tab: SettingsTab }
  | { kind: 'dualToggle'; key: string; row: number; column: number }
  | { kind: 'openCompanion'; key: string; row: number; column: number }
  | { kind: 'directTargeting'; key: string; row: number; column: number }
  | { kind: 'touchLock'; key: string; row: number; column: number }
  | { kind: 'iconStyle'; key: string; row: number; column: number; style: keyof typeof CONTROLLER_STYLE_LABELS }
  | { kind: 'device'; key: string; row: number; column: number; device: InputDevice }
  | { kind: 'binding'; key: string; row: number; column: number; action: InputAction }
  | { kind: 'resetBindings'; key: string; row: number; column: number }

const CONTROLLER_STYLE_LABELS = {
  xbox: 'Xbox',
  playstation: 'PlayStation',
  nintendo: 'Nintendo',
} as const

const SETTINGS_TAB_ORDER = ['display', 'input', 'bindings'] as const
const SETTINGS_TAB_LABELS: Record<SettingsTab, string> = {
  display: 'Display',
  input: 'Input',
  bindings: 'Bindings',
}
const SETTINGS_BINDING_COLUMNS = 2
const DIRECT_TARGET_ACTIONS = new Set<InputAction>([
  'targetParty1',
  'targetParty2',
  'targetParty3',
  'targetParty4',
  'targetParty5',
  'targetParty6',
  'toggleTargetGroup',
])

export function SettingsScreen({ onBack }: { onBack: () => void }) {
  const [device, setDevice] = useState<InputDevice>('controller')
  const [settingsTab, setSettingsTab] = useState<SettingsTab>('display')
  const [selectedIndex, setSelectedIndex] = useState(1)
  const [displayMessage, setDisplayMessage] = useState('')
  const [androidDisplays, setAndroidDisplays] = useState<AndroidDisplay[]>([])
  const navRefs = useRef<Record<string, HTMLElement | null>>({})
  const {
    bindings,
    capture,
    controllerIconStyle,
    directPartyTargeting,
    combatTouchLocked,
    beginCapture,
    cancelCapture,
    resetBindings,
    setControllerIconStyle,
    setDirectPartyTargeting,
    setCombatTouchLocked,
  } = useInput()
  const {
    enabled: dualScreenEnabled,
    connected: topDisplayConnected,
    setEnabled: setDualScreenEnabled,
    openTopDisplay,
  } = useDualScreen()
  const nativeDualScreen = hasNativeDualScreenBridge()
  const visibleActions = useMemo(() => INPUT_ACTIONS.filter((action) => (
    directPartyTargeting
      ? action !== 'previousTarget' && action !== 'nextTarget'
      : !DIRECT_TARGET_ACTIONS.has(action)
  )), [directPartyTargeting])
  const navEntries = useMemo<SettingsNavEntry[]>(() => {
    const entries: SettingsNavEntry[] = [
      { kind: 'back', key: 'back', row: 0, column: 0 },
      ...SETTINGS_TAB_ORDER.map((tab, index) => ({
        kind: 'tab' as const,
        key: `tab:${tab}`,
        row: 0,
        column: index + 1,
        tab,
      })),
    ]
    if (settingsTab === 'display') {
      entries.push(
        { kind: 'dualToggle', key: 'display:dual-toggle', row: 1, column: 1 },
        { kind: 'openCompanion', key: 'display:open-companion', row: 1, column: 2 },
      )
    } else if (settingsTab === 'input') {
      entries.push(
        { kind: 'directTargeting', key: 'input:direct-targeting', row: 1, column: 1 },
        { kind: 'touchLock', key: 'input:touch-lock', row: 1, column: 2 },
        { kind: 'iconStyle', key: 'input:icons:xbox', row: 2, column: 0, style: 'xbox' },
        { kind: 'iconStyle', key: 'input:icons:playstation', row: 2, column: 1, style: 'playstation' },
        { kind: 'iconStyle', key: 'input:icons:nintendo', row: 2, column: 2, style: 'nintendo' },
      )
    } else {
      entries.push(
        { kind: 'device', key: 'bindings:device:controller', row: 1, column: 0, device: 'controller' },
        { kind: 'device', key: 'bindings:device:pc', row: 1, column: 1, device: 'pc' },
        ...visibleActions.map((action, index) => ({
          kind: 'binding' as const,
          key: `bindings:action:${action}`,
          row: Math.floor(index / SETTINGS_BINDING_COLUMNS) + 2,
          column: index % SETTINGS_BINDING_COLUMNS,
          action,
        })),
        {
          kind: 'resetBindings',
          key: 'bindings:reset',
          row: Math.floor((visibleActions.length - 1) / SETTINGS_BINDING_COLUMNS) + 3,
          column: 1,
        },
      )
    }
    return entries
  }, [settingsTab, visibleActions])
  const activeIndex = Math.min(selectedIndex, Math.max(0, navEntries.length - 1))
  const activeEntry = navEntries[activeIndex]

  function selected(entryKey: string) {
    return activeEntry?.key === entryKey
  }

  function navRef(entryKey: string) {
    return (node: HTMLElement | null) => {
      navRefs.current[entryKey] = node
    }
  }

  function selectKey(entryKey: string) {
    const index = navEntries.findIndex((entry) => entry.key === entryKey)
    if (index >= 0) setSelectedIndex(index)
  }

  function selectTab(tab: SettingsTab) {
    setSettingsTab(tab)
    const tabIndex = SETTINGS_TAB_ORDER.indexOf(tab)
    setSelectedIndex(tabIndex + 1)
  }

  function firstContentKey(tab: SettingsTab) {
    if (tab === 'display') return 'display:dual-toggle'
    if (tab === 'input') return 'input:direct-targeting'
    return 'bindings:device:controller'
  }

  function moveSelection(action: InputAction) {
    if (!action.startsWith('navigate') || navEntries.length === 0) return
    setSelectedIndex((current) => {
      const bounded = Math.min(current, navEntries.length - 1)
      const active = navEntries[bounded]
      if (!active) return 0
      if (action === 'navigateDown' && active.row === 0) {
        const nextIndex = navEntries.findIndex((entry) => entry.key === firstContentKey(settingsTab))
        if (nextIndex >= 0) return nextIndex
      }
      if (action === 'navigateUp' && active.row === 1) {
        const tabIndex = navEntries.findIndex((entry) => entry.key === `tab:${settingsTab}`)
        if (tabIndex >= 0) return tabIndex
      }
      const candidates = navEntries
        .map((entry, index) => ({ entry, index }))
        .filter(({ index }) => index !== bounded)
        .filter(({ entry }) => {
          if (action === 'navigateLeft') return entry.column < active.column
          if (action === 'navigateRight') return entry.column > active.column
          if (action === 'navigateUp') return entry.row < active.row
          return entry.row > active.row
        })
      if (candidates.length === 0) return bounded
      candidates.sort((a, b) => {
        const aPrimary = Math.abs(a.entry.row - active.row) + Math.abs(a.entry.column - active.column)
        const bPrimary = Math.abs(b.entry.row - active.row) + Math.abs(b.entry.column - active.column)
        const aSecondary = action === 'navigateLeft' || action === 'navigateRight'
          ? Math.abs(a.entry.row - active.row)
          : Math.abs(a.entry.column - active.column)
        const bSecondary = action === 'navigateLeft' || action === 'navigateRight'
          ? Math.abs(b.entry.row - active.row)
          : Math.abs(b.entry.column - active.column)
        return aPrimary - bPrimary || aSecondary - bSecondary || a.index - b.index
      })
      return candidates[0]?.index ?? bounded
    })
  }

  function openEntry(entry: SettingsNavEntry | undefined) {
    if (!entry) return
    if (entry.kind === 'back') onBack()
    else if (entry.kind === 'tab') selectTab(entry.tab)
    else if (entry.kind === 'dualToggle') {
      setDualScreenEnabled(!dualScreenEnabled)
      setDisplayMessage('')
    } else if (entry.kind === 'openCompanion') {
      void launchTopDisplay()
    } else if (entry.kind === 'directTargeting') setDirectPartyTargeting(!directPartyTargeting)
    else if (entry.kind === 'touchLock') setCombatTouchLocked(!combatTouchLocked)
    else if (entry.kind === 'iconStyle') setControllerIconStyle(entry.style)
    else if (entry.kind === 'device') setDevice(entry.device)
    else if (entry.kind === 'binding') beginCapture(device, entry.action)
    else if (entry.kind === 'resetBindings') resetBindings(device)
  }

  async function refreshNativeDisplays() {
    if (!nativeDualScreen) return
    try {
      const result = await getNativeDisplays()
      setAndroidDisplays(result.displays)
    } catch {
      setAndroidDisplays([])
    }
  }

  useEffect(() => {
    if (!nativeDualScreen) return
    getNativeDisplays()
      .then((result) => setAndroidDisplays(result.displays))
      .catch(() => setAndroidDisplays([]))
  }, [nativeDualScreen])

  useEffect(() => {
    if (!activeEntry) return
    navRefs.current[activeEntry.key]?.scrollIntoView({ block: 'nearest', inline: 'nearest' })
  }, [activeEntry])

  useGameAction((action, inputDevice) => {
    if (inputDevice !== 'controller' || capture) return
    if (action === 'back') {
      onBack()
      return
    }
    if (action === 'confirm') {
      openEntry(activeEntry)
      return
    }
    moveSelection(action)
  })

  async function launchTopDisplay() {
    const opened = await openTopDisplay()
    setDisplayMessage(opened
      ? nativeDualScreen
        ? 'Android placed the game on the larger display and controls on the smaller display.'
        : 'Companion display opened. Move it to the Thor screen you want and select Fullscreen.'
      : 'No usable second display was found. Check the Thor display mode and try again.')
    await refreshNativeDisplays()
  }

  return (
    <section className="content-screen settings-screen" data-game-nav-active={capture ? undefined : 'true'}>
      <div className="settings-nav">
        <button
          className={`back-button settings-back-button ${selected('back') ? 'game-selected' : ''}`}
          data-controller-nav="skip"
          data-game-selected={selected('back') ? 'true' : undefined}
          onClick={onBack}
          onPointerDown={() => selectKey('back')}
          ref={navRef('back')}
          type="button"
        >
          Back
        </button>
        <nav className="settings-tabs" role="tablist" aria-label="Settings sections">
          {SETTINGS_TAB_ORDER.map((tab) => (
            <button
              aria-selected={settingsTab === tab}
              className={`${settingsTab === tab ? 'selected' : ''} ${selected(`tab:${tab}`) ? 'game-selected' : ''}`}
              data-controller-nav="skip"
              data-game-selected={selected(`tab:${tab}`) ? 'true' : undefined}
              key={tab}
              onClick={() => selectTab(tab)}
              onPointerDown={() => selectKey(`tab:${tab}`)}
              ref={navRef(`tab:${tab}`)}
              role="tab"
              type="button"
            >
              {SETTINGS_TAB_LABELS[tab]}
            </button>
          ))}
        </nav>
      </div>

      {settingsTab === 'display' && (
        <section className="dual-screen-settings settings-tab-panel">
          <div>
            <p className="eyebrow">Display</p>
            <h2>AYN Thor Dual-Screen Mode</h2>
            <p>
              The upper display shows enemy and party health. The lower display
              keeps targeting, resources, skills, and cooldowns.
            </p>
          </div>
          <div className="dual-screen-actions">
            <button
              className={`${dualScreenEnabled ? 'selected' : ''} ${selected('display:dual-toggle') ? 'game-selected' : ''}`}
              data-controller-nav="skip"
              data-game-selected={selected('display:dual-toggle') ? 'true' : undefined}
              onClick={() => {
                setDualScreenEnabled(!dualScreenEnabled)
                setDisplayMessage('')
              }}
              onPointerDown={() => selectKey('display:dual-toggle')}
              ref={navRef('display:dual-toggle')}
              type="button"
            >
              {dualScreenEnabled ? 'Dual-Screen Enabled' : 'Enable Dual-Screen'}
            </button>
            <button
              className={selected('display:open-companion') ? 'game-selected' : ''}
              data-controller-nav="skip"
              data-game-selected={selected('display:open-companion') ? 'true' : undefined}
              onClick={launchTopDisplay}
              onPointerDown={() => selectKey('display:open-companion')}
              ref={navRef('display:open-companion')}
              type="button"
            >
              {topDisplayConnected ? 'Companion Connected' : 'Open Companion Display'}
            </button>
          </div>
          <small>
            {displayMessage || (
              topDisplayConnected
                ? 'The companion display is connected and receiving live combat data.'
                : 'Open the companion display before starting combat.'
            )}
          </small>
          {nativeDualScreen && androidDisplays.length > 0 && (
            <div className="android-display-list">
              {androidDisplays.map((display) => (
                <span key={display.id}>
                  <strong>{display.isCurrent ? 'Current' : 'Secondary'} #{display.id}</strong>
                  {display.width}x{display.height} at {Math.round(display.refreshRate)} Hz
                  {display.isPresentation ? ' - Presentation' : ''}
                </span>
              ))}
            </div>
          )}
        </section>
      )}

      {settingsTab === 'input' && (
        <section className="controller-preferences settings-tab-panel">
          <div>
            <p className="eyebrow">Targeting</p>
            <h3>Direct Party Keybinds</h3>
            <p>
              Assign party slots directly. In raids, use the group-switch binding
              to alternate between members 1-6, 7-12, and 13-18.
            </p>
          </div>
          <button
            aria-pressed={directPartyTargeting}
            className={`${directPartyTargeting ? 'selected' : ''} ${selected('input:direct-targeting') ? 'game-selected' : ''}`}
            data-controller-nav="skip"
            data-game-selected={selected('input:direct-targeting') ? 'true' : undefined}
            onClick={() => setDirectPartyTargeting(!directPartyTargeting)}
            onPointerDown={() => selectKey('input:direct-targeting')}
            ref={navRef('input:direct-targeting')}
            type="button"
          >
            {directPartyTargeting ? 'Direct Targeting On' : 'Direct Targeting Off'}
          </button>
          <button
            aria-pressed={combatTouchLocked}
            className={`${combatTouchLocked ? 'selected' : ''} ${selected('input:touch-lock') ? 'game-selected' : ''}`}
            data-controller-nav="skip"
            data-game-selected={selected('input:touch-lock') ? 'true' : undefined}
            onClick={() => setCombatTouchLocked(!combatTouchLocked)}
            onPointerDown={() => selectKey('input:touch-lock')}
            ref={navRef('input:touch-lock')}
            type="button"
          >
            {combatTouchLocked ? 'Combat Touch Locked' : 'Combat Touch Unlocked'}
          </button>
          <div className="controller-icon-options">
            <span>Controller Icons</span>
            {(['xbox', 'playstation', 'nintendo'] as const).map((style) => (
              <button
                aria-pressed={controllerIconStyle === style}
                className={`${controllerIconStyle === style ? 'selected' : ''} ${selected(`input:icons:${style}`) ? 'game-selected' : ''}`}
                data-controller-nav="skip"
                data-game-selected={selected(`input:icons:${style}`) ? 'true' : undefined}
                key={style}
                onClick={() => setControllerIconStyle(style)}
                onPointerDown={() => selectKey(`input:icons:${style}`)}
                ref={navRef(`input:icons:${style}`)}
                type="button"
              >
                <ControllerStylePreview iconStyle={style} />
                <span className="controller-style-name">{CONTROLLER_STYLE_LABELS[style]}</span>
              </button>
            ))}
          </div>
        </section>
      )}

      {settingsTab === 'bindings' && (
        <section className="settings-bindings-panel settings-tab-panel">
          <div className="settings-heading">
            <div>
              <p className="eyebrow">Input</p>
              <h2>Keybindings</h2>
            </div>
            <p>Select an action, then press the new key or controller control.</p>
          </div>

          <div className="binding-tabs">
            <button
              className={`${device === 'controller' ? 'selected' : ''} ${selected('bindings:device:controller') ? 'game-selected' : ''}`}
              data-controller-nav="skip"
              data-game-selected={selected('bindings:device:controller') ? 'true' : undefined}
              onClick={() => setDevice('controller')}
              onPointerDown={() => selectKey('bindings:device:controller')}
              ref={navRef('bindings:device:controller')}
              type="button"
            >
              Controller
            </button>
            <button
              className={`${device === 'pc' ? 'selected' : ''} ${selected('bindings:device:pc') ? 'game-selected' : ''}`}
              data-controller-nav="skip"
              data-game-selected={selected('bindings:device:pc') ? 'true' : undefined}
              onClick={() => setDevice('pc')}
              onPointerDown={() => selectKey('bindings:device:pc')}
              ref={navRef('bindings:device:pc')}
              type="button"
            >
              PC
            </button>
          </div>

          <div className="binding-list">
            {visibleActions.map((action) => (
              <button
                className={`${capture?.device === device && capture.action === action ? 'listening' : ''} ${selected(`bindings:action:${action}`) ? 'game-selected' : ''}`}
                data-controller-nav="skip"
                data-game-selected={selected(`bindings:action:${action}`) ? 'true' : undefined}
                key={action}
                onClick={() => beginCapture(device, action)}
                onPointerDown={() => selectKey(`bindings:action:${action}`)}
                ref={navRef(`bindings:action:${action}`)}
                type="button"
              >
                <span>{ACTION_LABELS[action]}</span>
                <kbd>
                  {capture?.device === device && capture.action === action
                    ? 'Press a control...'
                    : (
                      <ControllerBindingLabel
                        binding={bindings[device][action]}
                        iconStyle={controllerIconStyle}
                      />
                    )}
                </kbd>
              </button>
            ))}
          </div>

          <footer className="settings-footer">
            <span>Bindings are saved automatically on this device.</span>
            <button
              className={`text-button ${selected('bindings:reset') ? 'game-selected' : ''}`}
              data-controller-nav="skip"
              data-game-selected={selected('bindings:reset') ? 'true' : undefined}
              onClick={() => resetBindings(device)}
              onPointerDown={() => selectKey('bindings:reset')}
              ref={navRef('bindings:reset')}
              type="button"
            >
              Reset {device === 'pc' ? 'PC' : 'Controller'} Defaults
            </button>
          </footer>
        </section>
      )}

      {capture && (
        <div className="binding-capture" role="dialog" aria-modal="true">
          <div>
            <p className="eyebrow">Remapping</p>
            <h2>{ACTION_LABELS[capture.action]}</h2>
            <p>
              Press any {capture.device === 'pc' ? 'keyboard key' : 'controller button or move a stick'}.
            </p>
            <button onClick={cancelCapture} type="button">Cancel</button>
          </div>
        </div>
      )}
    </section>
  )
}
