import {
  createContext,
  ReactNode,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState
} from 'react'
import { createPortal } from 'react-dom'
import { motion } from 'framer-motion'
import {
  BookOpen,
  Bug,
  Clock,
  Folder,
  KanbanSquare,
  Keyboard,
  LayoutDashboard,
  LogOut,
  Monitor,
  Moon,
  PanelLeftClose,
  PanelLeftOpen,
  Pencil,
  Plus,
  Search,
  ShieldCheck,
  Sun,
  Users,
  WifiOff
} from 'lucide-react'
import { useApp } from '../lib/AppContext'
import { useFeedback } from '../lib/feedback'
import { humanize } from '../lib/db'
import { Theme, ResolvedTheme, getTheme, resolveTheme, setTheme, watchSystemTheme } from '../lib/theme'
import { Page, plural } from '../lib/types'
import { currentVersion } from '../lib/updater'
import { Avatar } from './people'
import { Button, IconButton, Kbd } from './ui'
import { Modal, ModalActions } from './Modal'
import { Select } from './Select'
import NotificationBell from './NotificationBell'
import UpdateBanner, { UpdateCheckRow } from './UpdateBanner'
import CommandPalette from './CommandPalette'
import ProjectModal from './ProjectModal'
import Logo from './Logo'

export type { Page }

export const NAV: {
  id: Page
  label: string
  short: string
  icon: typeof LayoutDashboard
  adminOnly?: boolean
}[] = [
  { id: 'dashboard', label: 'Tableau de bord', short: 'Accueil', icon: LayoutDashboard },
  { id: 'kanban', label: 'Tâches', short: 'Tâches', icon: KanbanSquare },
  { id: 'planning', label: 'Feuille de temps', short: 'Temps', icon: Clock },
  { id: 'bugs', label: 'Bugs', short: 'Bugs', icon: Bug },
  { id: 'docs', label: 'Documentation', short: 'Doc', icon: BookOpen },
  { id: 'members', label: 'Équipe', short: 'Équipe', icon: Users },
  { id: 'admin', label: 'Administration', short: 'Admin', icon: ShieldCheck, adminOnly: true }
]

// ---------------------------------------------------------------------
//  Barre supérieure partagée
//
//  Avant, l'application empilait DEUX barres : un bandeau global de 48 px
//  quasi vide, plus l'en-tête propre à chaque page. Désormais il n'y en a
//  qu'une : le titre vient de la navigation, et chaque page y injecte ses
//  actions via <PageActions> (un portal) et son sous-titre via
//  usePageSubtitle().
// ---------------------------------------------------------------------

interface PageChrome {
  slot: HTMLElement | null
  setSubtitle: (s: string | null) => void
}

const ChromeCtx = createContext<PageChrome>({ slot: null, setSubtitle: () => undefined })

/** Boutons d'action de la page courante, rendus dans la barre supérieure. */
export function PageActions({ children }: { children: ReactNode }): JSX.Element | null {
  const { slot } = useContext(ChromeCtx)
  if (!slot) return null
  return createPortal(<>{children}</>, slot)
}

/**
 * Sous-titre contextuel de la page (« 3 bugs actifs », la semaine en cours…).
 *
 * ⚠️ Passe une CHAÎNE (ou une valeur mémoïsée) : la valeur est stockée dans un
 * état, donc un élément JSX recréé à chaque rendu ferait boucler la page.
 */
export function usePageSubtitle(subtitle: string | null): void {
  const { setSubtitle } = useContext(ChromeCtx)
  useEffect(() => {
    setSubtitle(subtitle)
    return () => setSubtitle(null)
  }, [subtitle, setSubtitle])
}

// ---------------------------------------------------------------------

const SIDEBAR_KEY = 'gamedev-tracker-sidebar'

export default function Layout({ children }: { children: ReactNode }): JSX.Element {
  const { page, setPage, profile, projects, currentProject, online, signOut } = useApp()

  const [collapsed, setCollapsed] = useState(() => localStorage.getItem(SIDEBAR_KEY) === '1')
  const [showNewProject, setShowNewProject] = useState(false)
  const [showHelp, setShowHelp] = useState(false)
  const [showPalette, setShowPalette] = useState(false)
  const [editProfile, setEditProfile] = useState(false)

  const [theme, setThemeState] = useState<Theme>(getTheme())
  const [resolved, setResolved] = useState<ResolvedTheme>(() => resolveTheme(getTheme()))

  const [slot, setSlot] = useState<HTMLElement | null>(null)
  const [subtitle, setSubtitle] = useState<string | null>(null)

  const nav = useMemo(() => NAV.filter((n) => !n.adminOnly || profile?.is_admin), [profile?.is_admin])
  const active = nav.find((n) => n.id === page) ?? nav[0]

  const toggleSidebar = useCallback(() => {
    setCollapsed((c) => {
      localStorage.setItem(SIDEBAR_KEY, c ? '0' : '1')
      return !c
    })
  }, [])

  /** clair → sombre → système → clair */
  const cycleTheme = useCallback(() => {
    setThemeState((cur) => {
      const next: Theme = cur === 'light' ? 'dark' : cur === 'dark' ? 'system' : 'light'
      setResolved(setTheme(next))
      return next
    })
  }, [])

  useEffect(() => watchSystemTheme(setResolved), [])

  // Raccourcis globaux. Tous avec Ctrl/Cmd : une touche seule changeait le
  // thème ou la page par simple frappe involontaire.
  useEffect(() => {
    const onKey = (e: globalThis.KeyboardEvent): void => {
      const mod = e.ctrlKey || e.metaKey
      const el = document.activeElement as HTMLElement | null
      const typing =
        !!el && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable)

      if (mod && e.key.toLowerCase() === 'k') {
        e.preventDefault()
        setShowPalette(true)
        return
      }
      if (!typing && e.key === '/') {
        e.preventDefault()
        setShowPalette(true)
        return
      }
      if (mod && e.key.toLowerCase() === 'b') {
        e.preventDefault()
        toggleSidebar()
        return
      }
      if (!typing && e.key === '?') {
        e.preventDefault()
        setShowHelp(true)
        return
      }
      if (mod && !e.shiftKey && /^[1-9]$/.test(e.key)) {
        const target = nav[Number(e.key) - 1]
        if (target) {
          e.preventDefault()
          setPage(target.id)
        }
      }
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [nav, setPage, toggleSidebar])

  const ThemeIcon = theme === 'system' ? Monitor : resolved === 'dark' ? Moon : Sun
  const themeLabel =
    theme === 'system' ? 'Thème : système' : theme === 'dark' ? 'Thème : sombre' : 'Thème : clair'

  const chrome = useMemo<PageChrome>(() => ({ slot, setSubtitle }), [slot])

  return (
    <ChromeCtx.Provider value={chrome}>
      <div className="flex h-full">
        {/* ------------------------------ Barre latérale ------------------------------ */}
        <aside
          className={`flex shrink-0 flex-col border-r border-border bg-sidebar transition-[width] duration-200 ease-smooth ${
            collapsed ? 'w-[3.75rem]' : 'w-60'
          }`}
        >
          <div className={`flex h-14 items-center gap-2.5 ${collapsed ? 'justify-center px-2' : 'px-4'}`}>
            <Logo size={26} />
            {!collapsed && <span className="truncate font-semibold text-ink">GameDev Tracker</span>}
          </div>

          <ProjectSwitcher collapsed={collapsed} onCreate={() => setShowNewProject(true)} />

          <nav className="mt-3 flex-1 space-y-0.5 px-2" aria-label="Navigation principale">
            {nav.map((n) => {
              const on = page === n.id
              return (
                <button
                  key={n.id}
                  type="button"
                  onClick={() => setPage(n.id)}
                  title={collapsed ? n.label : undefined}
                  aria-current={on ? 'page' : undefined}
                  className={`relative flex w-full items-center gap-3 rounded-lg px-2.5 py-2 text-sm font-medium transition-colors ${
                    collapsed ? 'justify-center' : ''
                  } ${on ? 'text-accent' : 'text-muted hover:bg-hover hover:text-ink'}`}
                >
                  {on && (
                    <motion.span
                      layoutId="nav-active"
                      className="absolute inset-0 rounded-lg bg-accent/12 ring-1 ring-inset ring-accent/25"
                      transition={{ type: 'spring', stiffness: 400, damping: 32 }}
                    />
                  )}
                  <n.icon size={18} className="relative z-10 shrink-0" />
                  {!collapsed && <span className="relative z-10 truncate">{n.label}</span>}
                </button>
              )
            })}
          </nav>

          {/* Pied : utilisateur */}
          <div className="border-t border-border p-2">
            {collapsed ? (
              <div className="flex flex-col items-center gap-1">
                <button
                  type="button"
                  onClick={() => setEditProfile(true)}
                  title={`${profile?.full_name ?? ''} — modifier mon profil`}
                  className="rounded-full ring-offset-2 ring-offset-sidebar hover:ring-2 hover:ring-accent"
                >
                  <Avatar profile={profile} size={28} />
                </button>
                <IconButton size="sm" label={themeLabel} icon={<ThemeIcon size={16} />} onClick={cycleTheme} />
                <IconButton
                  size="sm"
                  tone="danger"
                  label="Se déconnecter"
                  icon={<LogOut size={16} />}
                  onClick={signOut}
                />
              </div>
            ) : (
              <div className="flex items-center gap-2">
                <button
                  type="button"
                  onClick={() => setEditProfile(true)}
                  className="flex min-w-0 flex-1 items-center gap-2 rounded-lg p-1 text-left transition-colors hover:bg-hover"
                >
                  <Avatar profile={profile} size={30} />
                  <span className="min-w-0 flex-1">
                    <span className="block truncate text-sm font-medium text-ink">
                      {profile?.full_name}
                    </span>
                    <span className="block truncate text-xs text-subtle">Modifier mon profil</span>
                  </span>
                  <Pencil size={14} className="shrink-0 text-subtle" />
                </button>
                <IconButton size="sm" label={themeLabel} icon={<ThemeIcon size={17} />} onClick={cycleTheme} />
                <IconButton
                  size="sm"
                  tone="danger"
                  label="Se déconnecter"
                  icon={<LogOut size={17} />}
                  onClick={signOut}
                />
              </div>
            )}
          </div>
        </aside>

        {/* ------------------------------ Contenu ------------------------------ */}
        <main className="flex min-w-0 flex-1 flex-col overflow-hidden">
          <UpdateBanner />

          {!online && (
            <div
              role="status"
              className="flex shrink-0 items-center justify-center gap-2 bg-amber-500/15 py-1.5 text-xs font-medium text-amber-700 dark:text-amber-300"
            >
              <WifiOff size={13} />
              Hors ligne — tes modifications ne seront pas enregistrées tant que la connexion n'est pas revenue.
            </div>
          )}

          {/* UNE seule barre supérieure pour toute l'application */}
          <header className="flex h-14 shrink-0 items-center gap-3 border-b border-border bg-panel px-4">
            <IconButton
              size="sm"
              label={collapsed ? 'Déployer le menu (Ctrl+B)' : 'Replier le menu (Ctrl+B)'}
              icon={collapsed ? <PanelLeftOpen size={17} /> : <PanelLeftClose size={17} />}
              onClick={toggleSidebar}
            />

            <div className="min-w-0">
              <h1 className="truncate text-[15px] font-semibold leading-tight text-ink">
                {active?.label}
              </h1>
              <p className="truncate text-xs leading-tight text-subtle">
                {subtitle ?? currentProject?.name ?? 'Aucun projet'}
              </p>
            </div>

            <div className="ml-auto flex items-center gap-2">
              {/* Actions injectées par la page courante */}
              <div ref={setSlot} className="flex items-center gap-2" />

              <span className="mx-1 h-6 w-px bg-border" />

              <button
                type="button"
                onClick={() => setShowPalette(true)}
                className="hidden items-center gap-2 rounded-lg border border-border bg-panel2 py-1.5 pl-2.5 pr-2 text-xs text-subtle transition-colors hover:border-border-strong hover:text-muted lg:flex"
              >
                <Search size={14} />
                Rechercher
                <Kbd>Ctrl K</Kbd>
              </button>
              <IconButton
                size="sm"
                label="Rechercher (Ctrl+K)"
                icon={<Search size={17} />}
                onClick={() => setShowPalette(true)}
                className="lg:hidden"
              />
              <IconButton
                size="sm"
                label="Raccourcis clavier (?)"
                icon={<Keyboard size={17} />}
                onClick={() => setShowHelp(true)}
              />
              <NotificationBell />
            </div>
          </header>

          <div className="min-h-0 flex-1 overflow-hidden">
            {currentProject || page === 'admin' || page === 'members' ? (
              children
            ) : (
              <NoProject
                loading={projects.length === 0}
                onCreate={() => setShowNewProject(true)}
              />
            )}
          </div>
        </main>

        {showNewProject && <ProjectModal mode="create" onClose={() => setShowNewProject(false)} />}
        {editProfile && profile && <ProfileModalLazy onClose={() => setEditProfile(false)} />}
        {showHelp && <ShortcutsModal nav={nav} onClose={() => setShowHelp(false)} />}
        {showPalette && <CommandPalette onClose={() => setShowPalette(false)} />}
      </div>
    </ChromeCtx.Provider>
  )
}

// ---------------------------------------------------------------------
//  Sélecteur de projet
//  (l'ancien menu maison ne se fermait ni au clic extérieur ni à Échap)
// ---------------------------------------------------------------------

function ProjectSwitcher({
  collapsed,
  onCreate
}: {
  collapsed: boolean
  onCreate: () => void
}): JSX.Element | null {
  const { projects, currentProject, selectProject, projectsLoading } = useApp()

  if (collapsed) {
    return (
      <div className="flex justify-center px-2">
        <IconButton
          size="sm"
          label={currentProject?.name ?? 'Aucun projet'}
          icon={<Folder size={17} />}
          onClick={onCreate}
        />
      </div>
    )
  }

  if (projectsLoading) return <div className="mx-3 h-[42px] skeleton" />

  const NEW = '__new__'

  return (
    <div className="px-3">
      <Select
        ariaLabel="Changer de projet"
        placeholder="Aucun projet"
        className="!bg-panel"
        value={currentProject?.id ?? ''}
        onChange={(id) => {
          if (id === NEW) {
            onCreate()
            return
          }
          const p = projects.find((x) => x.id === id)
          if (p) selectProject(p)
        }}
        options={[
          ...projects.map((p) => ({
            value: p.id,
            label: p.name,
            hint: p.description ?? undefined,
            group: 'Projets'
          })),
          { value: NEW, label: '+ Nouveau projet', group: 'Gérer' }
        ]}
      />
    </div>
  )
}

// ---------------------------------------------------------------------

function NoProject({ loading, onCreate }: { loading: boolean; onCreate: () => void }): JSX.Element {
  const { projectsLoading, projectsError, refreshProjects } = useApp()

  // Avant, « Aucun projet » clignotait pendant le chargement.
  if (projectsLoading || (loading && !projectsError)) {
    return (
      <div className="flex h-full items-center justify-center">
        <div className="w-72 space-y-3">
          <div className="skeleton h-6 w-1/2" />
          <div className="skeleton h-24 w-full" />
        </div>
      </div>
    )
  }

  if (projectsError) {
    return (
      <div className="flex h-full items-center justify-center p-6">
        <div className="max-w-md text-center">
          <p className="mb-3 text-sm text-muted">{projectsError}</p>
          <Button onClick={refreshProjects}>Réessayer</Button>
        </div>
      </div>
    )
  }

  return (
    <div className="flex h-full flex-col items-center justify-center gap-4 px-6 text-center">
      <Folder size={40} className="text-subtle" />
      <div>
        <p className="text-sm font-medium text-ink">Aucun projet pour le moment</p>
        <p className="mt-1 max-w-sm text-sm text-muted">
          Un projet regroupe les tâches, les bugs et le temps passé de ton jeu.
        </p>
      </div>
      <Button variant="primary" icon={<Plus size={16} />} onClick={onCreate}>
        Créer le premier projet
      </Button>
    </div>
  )
}

// ---------------------------------------------------------------------

function ShortcutsModal({
  nav,
  onClose
}: {
  nav: { id: Page; label: string }[]
  onClose: () => void
}): JSX.Element {
  const [version, setVersion] = useState<string | null>(null)
  useEffect(() => {
    currentVersion().then(setVersion)
  }, [])

  const groups: { title: string; rows: [string, string][] }[] = [
    {
      title: 'Général',
      rows: [
        ['Ctrl K', 'Rechercher / palette de commandes'],
        ['/', 'Rechercher'],
        ['Ctrl B', 'Replier ou déployer le menu'],
        ['?', 'Afficher cette aide'],
        ['Échap', 'Fermer une fenêtre']
      ]
    },
    {
      title: 'Navigation',
      rows: nav.map((n, i): [string, string] => [`Ctrl ${i + 1}`, n.label])
    },
    {
      title: 'Kanban',
      rows: [
        ['Espace', 'Prendre / déposer une carte au clavier'],
        ['← →', 'Changer de colonne (carte prise)'],
        ['↑ ↓', 'Monter / descendre (carte prise)']
      ]
    },
    {
      title: 'Écriture',
      rows: [['Ctrl ⏎', 'Envoyer un commentaire']]
    }
  ]

  return (
    <Modal title="Raccourcis clavier" onClose={onClose} footer={
      <ModalActions>
        <Button variant="primary" onClick={onClose}>Compris</Button>
      </ModalActions>
    }>
      <div className="space-y-4">
        {groups.map((g) => (
          <section key={g.title}>
            <h3 className="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-subtle">
              {g.title}
            </h3>
            <ul className="divide-y divide-border">
              {g.rows.map(([key, label]) => (
                <li key={key + label} className="flex items-center justify-between gap-4 py-1.5 text-sm">
                  <span className="text-ink">{label}</span>
                  <span className="flex shrink-0 gap-1">
                    {key.split(' ').map((k) => (
                      <Kbd key={k}>{k}</Kbd>
                    ))}
                  </span>
                </li>
              ))}
            </ul>
          </section>
        ))}
      </div>
      <p className="mt-4 text-xs text-subtle">
        Les raccourcis de navigation sont inactifs pendant la saisie de texte.
      </p>

      <div className="mt-4">
        <UpdateCheckRow version={version} />
      </div>
    </Modal>
  )
}

// ---------------------------------------------------------------------
//  Édition du profil — importée à la demande pour ne pas alourdir le shell.
// ---------------------------------------------------------------------

function ProfileModalLazy({ onClose }: { onClose: () => void }): JSX.Element | null {
  const { profile, refreshProfile } = useApp()
  const { toast } = useFeedback()
  const [Comp, setComp] = useState<null | React.ComponentType<{
    profile: NonNullable<typeof profile>
    onClose: () => void
    onSaved: () => Promise<void>
  }>>(null)

  useEffect(() => {
    import('./EditProfileModal')
      .then((m) => setComp(() => m.default))
      .catch((e) => {
        toast(humanize(e), 'error')
        onClose()
      })
  }, [onClose, toast])

  if (!Comp || !profile) return null
  return <Comp profile={profile} onClose={onClose} onSaved={refreshProfile} />
}

/** Petit utilitaire de libellé réexporté pour les pages. */
export { plural }
