import { Outlet, useLocation, useNavigate } from '@tanstack/react-router'
import { useEffect, useRef, useState } from 'react'
import {
  Activity,
  Bell,
  ChevronLeft,
  ChevronRight,
  FileCode,
  Globe,
  KeyRound,
  LayoutDashboard,
  ListTodo,
  LogOut,
  Menu,
  Moon,
  Network,
  PanelLeftClose,
  PanelLeftOpen,
  ScrollText,
  Server,
  Settings,
  Sun,
  Terminal,
  UserRound,
  Variable,
  X,
} from 'lucide-react'
import { useTheme } from '@/context/ThemeContext'
import { api } from '@/api'
import { usePublicSite, useSentence, useUser } from '@/api/hooks'
import { NodeSwitcher } from '@/components/business/NodeSwitcher'
import { SystemNotice } from '@/components/business/SystemNotice'
import { ToastHost } from '@/components/business/ToastHost'
import { resetAuthCache } from '@/lib/auth'
import { eventBus } from '@/lib/event-bus'
import { cn } from '@/components/ui'

const NAV_ITEMS = [
  { path: '/', icon: LayoutDashboard, label: '数据仪表', exact: true },
  { path: '/tasks', icon: ListTodo, label: '定时任务', exact: true },
  { path: '/agents', icon: Server, label: '远程执行', exact: true },
  { path: '/editor', icon: FileCode, label: '脚本编辑', exact: false },
  { path: '/history', icon: ScrollText, label: '执行历史', exact: true },
  { path: '/environments', icon: Variable, label: '变量机密', exact: true },
  { path: '/languages', icon: Globe, label: '语言依赖', exact: false },
  { path: '/terminal', icon: Terminal, label: '终端命令', exact: true },
  { path: '/notify', icon: Bell, label: '消息推送', exact: true },
  { path: '/logs', icon: KeyRound, label: '运行日志', exact: true },
  { path: '/monitor', icon: Activity, label: '系统监控', exact: true },
  { path: '/interconnect', icon: Network, label: '互联管理', exact: true },
  { path: '/settings', icon: Settings, label: '系统设置', exact: true },
] as const

const COLLAPSE_KEY = 'taskpool.sidebar.collapsed'

function isActive(pathname: string, path: string, exact: boolean) {
  if (exact) return pathname === path
  return pathname === path || pathname.startsWith(path + '/')
}

export default function Layout() {
  const location = useLocation()
  const navigate = useNavigate()
  const { theme, toggleTheme } = useTheme()
  const { data: site } = usePublicSite()
  const { data: sentenceData } = useSentence()
  const { data: user } = useUser()
  const [menuOpen, setMenuOpen] = useState(false)
  const [isMobile, setIsMobile] = useState(false)
  const [collapsed, setCollapsed] = useState(() => {
    try {
      return localStorage.getItem(COLLAPSE_KEY) === '1'
    } catch {
      return false
    }
  })
  const [userMenuOpen, setUserMenuOpen] = useState(false)
  const userMenuRef = useRef<HTMLDivElement>(null)

  const title = site?.title || '任务池'
  const sentence = sentenceData?.sentence || '欢迎使用任务池'
  const username = user?.username || '管理员'
  const sidebarCollapsed = !isMobile && collapsed

  useEffect(() => {
    document.title = title
    const icon = site?.icon
    if (icon) {
      let link = document.querySelector("link[rel='icon']") as HTMLLinkElement | null
      if (!link) {
        link = document.createElement('link')
        link.rel = 'icon'
        document.head.appendChild(link)
      }
      link.href = icon
    }
  }, [title, site?.icon])

  useEffect(() => {
    const check = () => setIsMobile(window.innerWidth < 1024)
    check()
    window.addEventListener('resize', check)
    return () => window.removeEventListener('resize', check)
  }, [])

  useEffect(() => {
    setMenuOpen(false)
    setUserMenuOpen(false)
  }, [location.pathname])

  useEffect(() => {
    eventBus.init()
  }, [])

  useEffect(() => {
    try {
      localStorage.setItem(COLLAPSE_KEY, collapsed ? '1' : '0')
    } catch {
      // ignore
    }
  }, [collapsed])

  useEffect(() => {
    function onDocClick(e: MouseEvent) {
      if (!userMenuRef.current) return
      if (!userMenuRef.current.contains(e.target as Node)) {
        setUserMenuOpen(false)
      }
    }
    document.addEventListener('mousedown', onDocClick)
    return () => document.removeEventListener('mousedown', onDocClick)
  }, [])

  async function logout() {
    try {
      await api.auth.logout()
    } catch {
      // ignore
    }
    resetAuthCache()
    window.location.href = '/login'
  }

  return (
    <div className="flex min-h-screen w-full bg-[var(--bg-primary)] text-[var(--text-primary)]">
      {isMobile && menuOpen && (
        <div className="fixed inset-0 z-40 bg-black/50 backdrop-blur-[1px]" onClick={() => setMenuOpen(false)} />
      )}

      <aside
        className={cn(
          'fixed inset-y-0 left-0 z-50 flex shrink-0 flex-col border-r border-[var(--border)] bg-[var(--bg-secondary)] transition-[width,transform] duration-200 ease-out lg:static lg:translate-x-0',
          sidebarCollapsed ? 'w-[52px]' : 'w-[200px]',
          isMobile && !menuOpen ? '-translate-x-full' : 'translate-x-0',
        )}
      >
        <div
          className={cn(
            'relative flex h-14 items-center border-b border-[var(--border)]',
            sidebarCollapsed ? 'justify-center px-1' : 'gap-2.5 px-4',
          )}
        >
          <div
            className={cn(
              'ms-on-accent flex shrink-0 select-none items-center justify-center rounded-md bg-[var(--bg-accent)] font-bold text-[var(--text-on-accent)]',
              sidebarCollapsed ? 'h-7 w-7 text-[12px]' : 'h-8 w-8 text-[13px]',
            )}
          >
            T
          </div>
          {!sidebarCollapsed && (
            <div className="min-w-0 flex-1">
              <div className="truncate text-[13px] font-semibold tracking-tight">{title}</div>
              <div className="truncate text-[10px] text-[var(--text-muted)]">TaskPool</div>
            </div>
          )}
          {isMobile && (
            <button
              className="rounded-md p-1.5 text-[var(--text-muted)] hover:bg-[var(--bg-tertiary)] hover:text-[var(--text-primary)]"
              onClick={() => setMenuOpen(false)}
            >
              <X size={16} strokeWidth={1.5} />
            </button>
          )}
        </div>

        <nav className={cn('flex flex-1 flex-col gap-0.5 overflow-y-auto py-3', sidebarCollapsed ? 'px-1.5' : 'px-2.5')}>
          {NAV_ITEMS.map(({ path, icon: Icon, label, exact }) => {
            const active = isActive(location.pathname, path, exact)
            return (
              <button
                key={path}
                title={sidebarCollapsed ? label : undefined}
                onClick={() => navigate({ to: path })}
                className={cn(
                  'group relative flex h-9 w-full items-center rounded-md text-[13px] transition-[background,color,border-color] duration-150',
                  sidebarCollapsed ? 'justify-center px-0' : 'gap-2.5 px-2.5',
                  active
                    ? 'border border-[var(--border-hover)] bg-[var(--bg-tertiary)] font-medium text-[var(--text-primary)]'
                    : 'border border-transparent text-[var(--text-secondary)] hover:bg-[var(--bg-hover)] hover:text-[var(--text-primary)]',
                )}
              >
                <Icon
                  size={15}
                  strokeWidth={1.5}
                  className={cn(active ? 'text-[var(--text-primary)]' : 'text-[var(--text-muted)] group-hover:text-[var(--text-primary)]')}
                />
                {!sidebarCollapsed && (
                  <>
                    <span className="truncate">{label}</span>
                    {active ? <span className="ml-auto h-1.5 w-1.5 rounded-full bg-[var(--bg-accent)]" /> : null}
                  </>
                )}
              </button>
            )
          })}
        </nav>
      </aside>

      <main className="flex min-w-0 flex-1 flex-col">
        <header className="sticky top-0 z-30 flex h-14 items-center justify-between border-b border-[var(--border)] bg-[color-mix(in_srgb,var(--bg-secondary)_92%,transparent)] px-4 backdrop-blur-md">
          <div className="flex min-w-0 flex-1 items-center gap-2">
            {isMobile ? (
              <button
                className="inline-flex h-8 w-8 items-center justify-center rounded-md text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] hover:text-[var(--text-primary)]"
                onClick={() => setMenuOpen(true)}
                title="打开菜单"
              >
                <Menu size={16} strokeWidth={1.5} />
              </button>
            ) : (
              <button
                className="inline-flex h-8 w-8 items-center justify-center rounded-md text-[var(--text-secondary)] hover:bg-[var(--bg-tertiary)] hover:text-[var(--text-primary)]"
                onClick={() => setCollapsed((v) => !v)}
                title={collapsed ? '展开侧边栏' : '收起侧边栏'}
              >
                {collapsed ? <PanelLeftOpen size={16} strokeWidth={1.5} /> : <PanelLeftClose size={16} strokeWidth={1.5} />}
              </button>
            )}
            <p className="truncate text-[13px] text-[var(--text-muted)]" title={sentence}>
              {sentence}
            </p>
          </div>

          {/* 顶栏工具统一 h-8，避免通知/主题/用户高度不一致 */}
          <div className="flex h-8 items-center gap-1.5">
            <NodeSwitcher />
            <SystemNotice />
            <button
              type="button"
              onClick={toggleTheme}
              title={theme === 'light' ? '深色模式' : '浅色模式'}
              className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-[var(--border)] bg-[var(--bg-primary)] text-[var(--text-secondary)] transition-colors hover:border-[var(--border-hover)] hover:bg-[var(--bg-tertiary)] hover:text-[var(--text-primary)]"
            >
              {theme === 'light' ? <Moon size={15} strokeWidth={1.5} /> : <Sun size={15} strokeWidth={1.5} />}
            </button>

            <div className="relative" ref={userMenuRef}>
              <button
                type="button"
                onClick={() => setUserMenuOpen((v) => !v)}
                className={cn(
                  'inline-flex h-8 items-center gap-1.5 rounded-md border border-[var(--border)] bg-[var(--bg-primary)] px-2 text-[12px] leading-none text-[var(--text-secondary)] transition-colors hover:border-[var(--border-hover)] hover:text-[var(--text-primary)]',
                  userMenuOpen && 'border-[var(--border-hover)] text-[var(--text-primary)]',
                )}
                title="账户"
              >
                <span className="inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-[var(--bg-tertiary)] text-[var(--text-muted)]">
                  <UserRound size={12} strokeWidth={1.75} />
                </span>
                <span className="hidden max-w-[96px] truncate sm:inline">{username}</span>
              </button>

              {userMenuOpen && (
                <div className="absolute right-0 top-[calc(100%+6px)] z-50 w-44 overflow-hidden rounded-lg border border-[var(--border)] bg-[var(--bg-secondary)] shadow-[0_12px_40px_rgba(0,0,0,0.18)]">
                  <div className="border-b border-[var(--border)] px-3 py-2.5">
                    <div className="truncate text-[12px] font-medium text-[var(--text-primary)]">{username}</div>
                    <div className="truncate text-[11px] text-[var(--text-muted)]">已登录</div>
                  </div>
                  <button
                    type="button"
                    onClick={() => {
                      setUserMenuOpen(false)
                      void logout()
                    }}
                    className="flex h-10 w-full items-center gap-2 px-3 text-[13px] text-[var(--text-secondary)] transition-colors hover:bg-[var(--bg-hover)] hover:text-[var(--danger)]"
                  >
                    <LogOut size={14} strokeWidth={1.5} />
                    退出登录
                  </button>
                </div>
              )}
            </div>
          </div>
        </header>

        <div className="ms-page flex-1 overflow-y-auto p-4 lg:p-6">
          <Outlet />
        </div>
      </main>
      <ToastHost />
    </div>
  )
}
