import { useEffect, useMemo, useState, type ReactNode } from 'react'
import { Link, NavLink, Outlet, useLocation, useNavigate } from 'react-router-dom'
import { ApiHttpError } from '../api/http'
import { fetchNavMenu } from '../api/session'
import type { NavItem } from '../api/types'
import { useAuth } from '../auth/AuthProvider'
import {
  isExternalNavUrl,
  spaPathFromCiUrl,
} from '../lib/ciSpaPaths'

const navLabelCollator = new Intl.Collator(undefined, {
  sensitivity: 'base',
  numeric: true,
})

function compareNavItemsByLabel(a: NavItem, b: NavItem): number {
  const labelResult = navLabelCollator.compare(a.label?.trim() || '', b.label?.trim() || '')
  return labelResult || a.id - b.id
}

function sortNavTree(items: NavItem[]): NavItem[] {
  return [...items]
    .map((item) => ({
      ...item,
      children: sortNavTree(item.children ?? []),
    }))
    .sort(compareNavItemsByLabel)
}

function normalizeNavItems(payload: unknown): NavItem[] {
  const rawItems = Array.isArray(payload)
    ? (payload as NavItem[])
    : payload &&
        typeof payload === 'object' &&
        'data' in payload &&
        Array.isArray((payload as { data: unknown }).data)
      ? ((payload as { data: NavItem[] }).data ?? [])
      : []

  if (rawItems.length === 0) return []
  if (rawItems.some((item) => Array.isArray(item.children) && item.children.length > 0)) {
    return sortNavTree(rawItems)
  }

  const byId = new Map<number, NavItem>()
  for (const item of rawItems) {
    byId.set(item.id, { ...item, children: [] })
  }

  const tree: NavItem[] = []
  for (const item of byId.values()) {
    const parentId = item.menu_parent_id ?? null
    if (parentId != null && byId.has(parentId)) {
      byId.get(parentId)?.children.push(item)
    } else {
      tree.push(item)
    }
  }

  return sortNavTree(tree)
}

function branchContainsPath(item: NavItem, pathname: string): boolean {
  const spa = item.url ? spaPathFromCiUrl(item.url) : null
  if (spa && pathname.startsWith(spa)) return true
  return (item.children ?? []).some((child) => branchContainsPath(child, pathname))
}

function NavTree({ items, pathname }: { items: NavItem[]; pathname: string }) {
  return (
    <ul className="nav flex-column gap-1 ps-0 mb-0 list-unstyled mgmt-nav-tree">
      {items.map((item) => (
        <NavBranch key={item.id} item={item} depth={0} pathname={pathname} />
      ))}
    </ul>
  )
}

function NavBranch({ item, depth, pathname }: { item: NavItem; depth: number; pathname: string }) {
  const enabled = item.is_enabled !== 0
  const label = item.label?.trim() || 'Menu'
  const url = item.url?.trim() || ''
  const external = isExternalNavUrl(url)
  const spa = spaPathFromCiUrl(url)
  const pad = 8 + depth * 10

  const icon = item.icon_class ? (
    <i className={`${item.icon_class} me-2`} aria-hidden />
  ) : null

  const children = sortNavTree((item.children ?? []).filter((c) => c.is_enabled !== 0))
  const hasChildren = children.length > 0
  const [open, setOpen] = useState(() => hasChildren && branchContainsPath(item, pathname))

  useEffect(() => {
    if (hasChildren && branchContainsPath(item, pathname)) {
      setOpen(true)
    }
  }, [hasChildren, item, pathname])

  if (!enabled) return null

  const linkInner = (
    <>
      {icon}
      <span className="nav-label-chip">{label}</span>
      {hasChildren ? (
        <i
          className={`bi ${open ? 'bi-chevron-down' : 'bi-chevron-right'} ms-auto`}
          aria-hidden
        />
      ) : null}
    </>
  )

  const linkClass = ({ isActive }: { isActive: boolean }) =>
    `nav-link rounded py-2 px-2 ${isActive ? 'active fw-semibold' : ''}`

  let main: ReactNode
  const handleBranchToggle = () => {
    if (hasChildren) {
      setOpen((value) => !value)
    }
  }

  if (external) {
    main = (
      <a
        className="nav-link rounded py-2 px-2"
        href={url}
        target={item.target || '_self'}
        rel={item.target === '_blank' ? 'noreferrer noopener' : undefined}
        style={{ paddingLeft: pad }}
        onClick={hasChildren ? (event) => {
          event.preventDefault()
          handleBranchToggle()
        } : undefined}
      >
        {linkInner}
      </a>
    )
  } else if (spa && !hasChildren) {
    main = (
      <NavLink end to={spa} className={linkClass} style={{ paddingLeft: pad }}>
        {linkInner}
      </NavLink>
    )
  } else if (spa && hasChildren) {
    main = (
      <button
        type="button"
        className="nav-link rounded py-2 px-2 w-100 text-start d-flex align-items-center"
        style={{ paddingLeft: pad }}
        aria-expanded={open}
        onClick={handleBranchToggle}
      >
        {linkInner}
      </button>
    )
  } else {
    main = (
      <button
        type="button"
        className="nav-link rounded py-2 px-2 w-100 text-start d-flex align-items-center border-0 bg-transparent"
        style={{ paddingLeft: pad }}
        aria-expanded={hasChildren ? open : undefined}
        onClick={hasChildren ? handleBranchToggle : undefined}
        disabled={!hasChildren}
      >
        {linkInner}
      </button>
    )
  }

  return (
    <li className={`mgmt-nav-branch mgmt-nav-depth-${Math.min(depth, 4)}`}>
      {main}
      {children.length > 0 && open ? (
        <ul className="nav flex-column gap-1 ps-0 mb-0 mt-1 list-unstyled mgmt-nav-subtree">
          {children.map((ch) => (
            <NavBranch key={ch.id} item={ch} depth={depth + 1} pathname={pathname} />
          ))}
        </ul>
      ) : null}
    </li>
  )
}

export function ManagementLayout() {
  const { user, logout } = useAuth()
  const navigate = useNavigate()
  const location = useLocation()
  const [items, setItems] = useState<NavItem[]>([])
  const [menuError, setMenuError] = useState<string | null>(null)
  const [sidebarOpen, setSidebarOpen] = useState(false)

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      try {
        const res = await fetchNavMenu()
        const list = res.data?.items
        if (!cancelled && list != null) {
          setItems(normalizeNavItems(list))
          setMenuError(null)
        }
      } catch (e) {
        if (!cancelled) {
          if (e instanceof ApiHttpError && e.status === 401) {
            logout()
            navigate('/login', {
              replace: true,
              state: {
                from: `${location.pathname}${location.search}${location.hash}`,
                message: 'Your session expired. Please sign in again.',
              },
            })
            return
          }
          setItems([])
          setMenuError(e instanceof Error ? e.message : 'Unable to load menu.')
        }
      }
    })()
    return () => {
      cancelled = true
    }
  }, [location.hash, location.pathname, location.search, logout, navigate])

  const navTree = useMemo(() => normalizeNavItems(items), [items])

  return (
    <div className={`management-app d-flex flex-column min-vh-100 ${sidebarOpen ? 'mgmt-sidebar-open' : ''}`}>
      <header className="navbar navbar-dark sticky-top border-bottom shadow-sm px-3 py-2">
        <div className="container-fluid px-2 d-flex flex-wrap align-items-center justify-content-between gap-2">
          <Link className="navbar-brand fw-semibold mb-0" to="/app/home">
            Al Rahma Sunday School
          </Link>
          <div className="d-flex align-items-center gap-2">
            <span className="navbar-text small mb-0">{user?.name}</span>
            <button
              type="button"
              className="btn btn-outline-light btn-sm"
              onClick={() => {
                logout()
                navigate('/login', { replace: true })
              }}
            >
              Log out
            </button>
          </div>
        </div>
      </header>

      <button
        id="mgmtSidebarToggle"
        className="mgmt-sidebar-toggle"
        type="button"
        aria-label="Toggle sidebar"
        aria-expanded={sidebarOpen}
        onClick={() => setSidebarOpen((open) => !open)}
      >
        <i className="bi bi-chevron-right" aria-hidden />
      </button>

      {sidebarOpen ? (
        <button
          className="mgmt-sidebar-backdrop"
          type="button"
          aria-label="Close navigation"
          onClick={() => setSidebarOpen(false)}
        />
      ) : null}

      <div className="wrapper flex-grow-1">
        <aside id="navbarManagement" className="mgmt-sidebar" data-mgmt-menu-mode="dark">
          <div className="mgmt-sidebar-content">
            <div className="mgmt-sidebar-header px-2 py-2 mb-2">
              <div className="mgmt-sidebar-eyebrow">Management</div>
              <div className="mgmt-sidebar-title">Navigation</div>
            </div>
            <nav className="pb-3">
                <NavLink
                  to="/app/home"
                  className={({ isActive }) =>
                    `nav-link rounded mb-2 mgmt-static-link ${isActive ? 'active fw-semibold' : ''}`
                  }
                >
                  <i className="bi bi-house-door me-2" aria-hidden />
                  <span className="nav-label-chip">Home</span>
                </NavLink>
                <NavLink
                  to="/app/browse"
                  className={({ isActive }) =>
                    `nav-link rounded mb-2 mgmt-static-link ${isActive ? 'active fw-semibold' : ''}`
                  }
                >
                  <i className="bi bi-diagram-3 me-2" aria-hidden />
                  <span className="nav-label-chip">CI views</span>
                </NavLink>
                {menuError ? (
                  <div className="alert alert-warning small py-2">{menuError}</div>
                ) : (
                  <NavTree items={navTree} pathname={location.pathname} />
                )}
              </nav>
            </div>
        </aside>

        <main className="content management-main">
            <Outlet />
        </main>
      </div>

      <footer className="footer-back border-top bg-white py-3 mt-auto">
        <div className="container-fluid px-4 text-muted small d-flex flex-wrap justify-content-between gap-2">
          <span>Al Rahma Sunday School</span>
          <span>Management Portal</span>
        </div>
      </footer>

      <div className="modal fade" id="familyCardModal" tabIndex={-1} aria-hidden="true">
        <div className="modal-dialog modal-xl modal-dialog-scrollable">
          <div className="modal-content">
            <div className="modal-header">
              <h5 className="modal-title">Family</h5>
              <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close" />
            </div>
            <div className="modal-body p-0" id="familyCardContent" />
          </div>
        </div>
      </div>

      <div className="modal fade" id="paymentsModal" tabIndex={-1} aria-hidden="true">
        <div className="modal-dialog modal-lg modal-dialog-scrollable">
          <div className="modal-content">
            <div className="modal-header">
              <h5 className="modal-title">Payments</h5>
              <button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close" />
            </div>
            <div className="modal-body p-0" id="paymentsModalContent" />
          </div>
        </div>
      </div>
    </div>
  )
}
