import { useState } from 'react'
import { Link, useLocation } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import {
  Home,
  Database,
  FileText,
  ClipboardList,
  Inbox,
  Webhook,
  ScrollText,
  Search,
  type LucideIcon,
} from 'lucide-react'
import { useAuth } from 'react-oidc-context'
import { useCanMutate } from '@/auth/useCanMutate'
import {
  useCanReviewRecord,
  useCanReviewSchema,
} from '@/auth/usePermissions'
import {
  useDictionaries,
  useMyDrafts,
  useMySchemaDrafts,
  useOutboxStats,
  useReviewsBadgeCount,
  useWebhookSubscriptions,
} from '@/api/queries'
import { Sheet, SheetContent } from '@/ui'
import { ThemeSwitch } from '@/components/layout/ThemeSwitch'
import { cn } from '@/lib/utils'

/**
 * Sidebar — 220px nav rail per handoff design system.
 *
 * Structure (top-to-bottom):
 *  - Logo block (ORDINIS wordmark в Tektur)
 *  - Section: navigation rail (Home, Справочники [count], Поиск, Граф)
 *  - Section: admin-only (Мои черновики, На ревью [count], Аудит, Outbox, Webhooks)
 *  - User profile (bottom, sticky)
 *
 * Responsive: на <1024px collapse в icon-only rail (56px). Smaller — overlay
 * drawer (TODO Stage 3.x). Сейчас always-visible — main grid сам адаптирует.
 */

type NavSection = {
  /** Optional .cap header above items. */
  label?: string
  items: NavItem[]
}

type NavItem = {
  to: string
  label: string
  icon: LucideIcon
  /** Badge content справа (число pending / counts). */
  badge?: React.ReactNode
  /** Только аутентифицированным пользователям. */
  authRequired?: boolean
  /**
   * Visible только если user имеет хотя бы одну из workflow ролей
   * (или {@code ordinis:admin} super-role). Hide если нет.
   */
  reviewerOnly?: boolean
}

export function Sidebar() {
  const { t } = useTranslation()
  const auth = useAuth()
  const canMutate = useCanMutate()
  // Phase 1d role-based sidebar visibility. /reviews пункт показываем
  // только тем у кого есть schema:reviewer OR record:reviewer OR
  // ordinis:admin super-role. Иначе пункт скрыт — у user'а нет смысла
  // его видеть (clicking всё равно даст empty queue / 403).
  const canReviewSchema = useCanReviewSchema()
  const canReviewRecord = useCanReviewRecord()
  const isReviewer = canReviewSchema || canReviewRecord
  const dictsQuery = useDictionaries()
  // Loaded just for сидбар counter — light request, кэшируется.
  // Badge "Мои черновики" суммирует record (/drafts/me) + schema
  // (/admin/schema-drafts/me) — maker не должен помнить разные типы.
  const myDrafts = useMyDrafts(0, 1)
  const mySchemaDrafts = useMySchemaDrafts(0, 1)
  // Reviews badge — суммирует record-reviews + schema-reviews pending queues
  // через size=1 paged запросы. Gated на authenticated.
  const reviews = useReviewsBadgeCount(auth.isAuthenticated)
  // Outbox/Webhooks badges — light periodic poll. Backend гейтит, поэтому
  // anonymous safe (просто 401 проигнорируется).
  const outboxStats = useOutboxStats()
  const webhooks = useWebhookSubscriptions()

  const dictsCount = dictsQuery.data?.length ?? 0
  const myDraftsCount =
    (myDrafts.data?.totalElements ?? 0) + (mySchemaDrafts.data?.totalElements ?? 0)
  const reviewsCount = reviews.total
  // Pending events ждут dispatch. dlq отдельно — alarming, но не блокирует
  // нормальную работу, можно увидеть на /outbox. Badge показывает только
  // pending (actionable: 'надо разобраться почему queue растёт').
  const outboxPending = outboxStats.data?.pending ?? 0
  const webhooksActive =
    webhooks.data?.filter((w) => w.active).length ?? 0

  // Flat list per redesign/compact.html — no section labels, /graph removed
  // (now reachable via catalog toolbar "Граф ⇄" button). Order: Главная →
  // Справочники → Мои черновики → На ревью → Outbox → Webhooks → Аудит → Поиск.
  const sections: NavSection[] = [
    {
      items: [
        { to: '/', label: t('nav.home'), icon: Home },
        {
          to: '/dictionaries',
          label: t('nav.dictionaries'),
          icon: Database,
          badge: dictsCount > 0 ? dictsCount : undefined,
        },
        {
          to: '/my-drafts',
          label: t('nav.myDrafts'),
          icon: FileText,
          badge: myDraftsCount > 0 ? myDraftsCount : undefined,
          authRequired: true,
        },
        {
          to: '/reviews',
          label: t('nav.reviews'),
          icon: ClipboardList,
          badge: reviewsCount > 0 ? reviewsCount : undefined,
          authRequired: true,
          reviewerOnly: true,
        },
        {
          to: '/outbox',
          label: t('nav.outbox'),
          icon: Inbox,
          badge: outboxPending > 0 ? outboxPending : undefined,
          authRequired: true,
        },
        {
          to: '/webhooks',
          label: t('nav.webhooks'),
          icon: Webhook,
          badge: webhooksActive > 0 ? webhooksActive : undefined,
          authRequired: true,
        },
        { to: '/audit', label: t('nav.audit'), icon: ScrollText, authRequired: true },
        { to: '/search', label: t('nav.search'), icon: Search },
      ],
    },
  ]

  const visibleSections = sections
    .map((s) => ({
      ...s,
      items: s.items.filter((i) => {
        if (i.authRequired && !canMutate) return false
        if (i.reviewerOnly && !isReviewer) return false
        return true
      }),
    }))
    .filter((s) => s.items.length > 0)

  // Sidebar collapsed mode — per handoff prototype 'Свернуть' button bottom-left.
  // Persists в localStorage. Collapsed = icon-only 56px rail, expanded = 220px.
  const [collapsed, setCollapsed] = useState<boolean>(() => {
    if (typeof window === 'undefined') return false
    return window.localStorage.getItem('ord-sidebar-collapsed') === '1'
  })
  const toggleCollapsed = () => {
    setCollapsed((prev) => {
      const next = !prev
      try {
        window.localStorage.setItem('ord-sidebar-collapsed', next ? '1' : '0')
      } catch {
        // localStorage может быть disabled
      }
      return next
    })
  }

  return (
    <aside
      className={cn(
        'hidden lg:flex shrink-0 flex-col border-r border-line bg-surface transition-[width] duration-200',
        collapsed ? 'w-[56px]' : 'w-[220px]',
      )}
    >
      <SidebarContent
        sections={visibleSections}
        auth={auth}
        collapsed={collapsed}
        onToggleCollapsed={toggleCollapsed}
      />
    </aside>
  )
}

/**
 * SidebarContent — внутренности (logo + nav + user). Используется в desktop
 * rail (Sidebar) И в mobile drawer (MobileSidebar) — DRY.
 */
function SidebarContent({
  sections,
  auth,
  onNavigate,
  collapsed = false,
  onToggleCollapsed,
}: {
  sections: NavSection[]
  auth: ReturnType<typeof useAuth>
  /** Called после клика на nav item — для close drawer в mobile mode. */
  onNavigate?: () => void
  /** Desktop collapse state — affects labels visibility и width. */
  collapsed?: boolean
  /** Toggle button handler. When undefined — collapse button hidden (mobile). */
  onToggleCollapsed?: () => void
}) {
  return (
    <>
      {/* Logo block per redesign prototype: circle (accent) + ORDINIS + MDM mute */}
      <div
        className={cn(
          'h-11 flex items-center border-b border-line shrink-0',
          collapsed ? 'justify-center px-2' : 'px-5 gap-2',
        )}
      >
        <Link
          to="/"
          className="flex items-center gap-2 hover:opacity-80 transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-sm"
          onClick={onNavigate}
          title="ORDINIS MDM"
        >
          {/* Ordinis mark — orbital structure recolored под Ordinis palette.
              При мелком размере (28px) тонкие линии/маленькие dots становились
              почти невидимыми. Bumped strokeWidth до 5 + dot radii до 14/11
              (внутри 256 viewBox = читаемые ~1.5px / 1.2px при 28px render).
              Theme-aware через currentColor + var(--color-line). */}
          <svg
            width="28"
            height="28"
            viewBox="0 0 256 256"
            fill="none"
            xmlns="http://www.w3.org/2000/svg"
            aria-hidden
            className="shrink-0 text-accent"
          >
            <g transform="translate(128 128)">
              {/* Outer orbits — line tone. Math: viewBox 256 при render 28px =
                * 0.11px/unit. stroke=12 даёт ~1.3px real — чёткая видимая линия. */}
              <circle r="96" fill="none" stroke="var(--color-line)" strokeWidth="12" />
              <circle r="62" fill="none" stroke="var(--color-line)" strokeWidth="12" />
              {/* Outer orbit dots (3) — large accent dots */}
              <circle cx="96" cy="0" r="16" fill="currentColor" />
              <circle cx="-48" cy="83.14" r="14" fill="currentColor" opacity="0.7" />
              <circle cx="-48" cy="-83.14" r="14" fill="currentColor" opacity="0.7" />
              {/* Inner orbit dots (3) */}
              <circle cx="-62" cy="0" r="13" fill="currentColor" />
              <circle cx="31" cy="-53.69" r="11" fill="currentColor" opacity="0.7" />
              <circle cx="31" cy="53.69" r="11" fill="currentColor" opacity="0.7" />
              {/* Core — solid accent, prominent */}
              <circle r="24" fill="currentColor" />
            </g>
          </svg>
          {!collapsed && (
            <span className="font-display text-title-md leading-none tracking-[0.22em] text-ink inline-flex items-baseline gap-1.5">
              ORDINIS
              <span className="text-mute font-normal tracking-[0.32em] text-[0.78em]">MDM</span>
            </span>
          )}
        </Link>
      </div>

      {/* Nav sections */}
      <nav className="flex-1 overflow-y-auto py-3 px-2 flex flex-col gap-4">
        {sections.map((section, idx) => (
          <div key={idx} className="flex flex-col gap-0.5">
            {section.label && !collapsed && (
              <div className="text-cap px-3 py-1 text-mute">{section.label}</div>
            )}
            {section.items.map((item) => (
              <SidebarLink key={item.to} {...item} onClick={onNavigate} collapsed={collapsed} />
            ))}
          </div>
        ))}
      </nav>

      {/* Footer: Lang toggle + User profile (or Sign-in) + Collapse toggle.
        * Moved from TopBar per user feedback: "вход в сайдбар, ru/en в сайдбаре". */}
      <SidebarFooter
        auth={auth}
        collapsed={collapsed}
        onToggleCollapsed={onToggleCollapsed}
      />
    </>
  )
}

function SidebarFooter({
  auth,
  collapsed,
  onToggleCollapsed,
}: {
  auth: ReturnType<typeof useAuth>
  collapsed: boolean
  onToggleCollapsed?: () => void
}) {
  const { t, i18n } = useTranslation()
  const cur = i18n.language?.toLowerCase().startsWith('en') ? 'en' : 'ru'
  const next = cur === 'ru' ? 'en-US' : 'ru-RU'

  return (
    <>
      {/* Language toggle + Theme switch row (только когда expanded).
        * ThemeSwitch и LanguageSwitch переехали из TopBar per user
        * ("свитч темы можно тоже в профиль перенести"). */}
      {!collapsed && (
        <div className="border-t border-line px-3 py-2 flex items-center gap-2 shrink-0">
          <button
            type="button"
            onClick={() => i18n.changeLanguage(next)}
            className="h-7 px-2.5 rounded-md border border-line bg-surface text-cap text-ink-2 hover:bg-surface-2 hover:text-ink transition-colors"
            aria-label={`Language: ${cur.toUpperCase()}, click to switch`}
          >
            {cur.toUpperCase()}
          </button>
          <div className="ml-auto">
            <ThemeSwitch />
          </div>
        </div>
      )}

      {/* Auth block: avatar + name (authed) OR Sign-in CTA (anonymous). */}
      {auth.isAuthenticated && auth.user?.profile ? (
        <AuthedUserBlock auth={auth} collapsed={collapsed} />
      ) : (
        <SignInCta auth={auth} collapsed={collapsed} />
      )}

      {/* Collapse toggle */}
      {onToggleCollapsed && (
        <button
          type="button"
          onClick={onToggleCollapsed}
          aria-label={collapsed
            ? t('sidebar.expand', { defaultValue: 'Развернуть' })
            : t('sidebar.collapse', { defaultValue: 'Свернуть' })
          }
          title={collapsed ? t('sidebar.expand', { defaultValue: 'Развернуть' }) : t('sidebar.collapse', { defaultValue: 'Свернуть' })}
          className={cn(
            'border-t border-line shrink-0 h-8 flex items-center gap-2 text-cap text-mute hover:text-ink hover:bg-surface-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
            collapsed ? 'justify-center' : 'px-4',
          )}
        >
          <span aria-hidden>{collapsed ? '›' : '‹'}</span>
          {!collapsed && (
            <span>{t('sidebar.collapse', { defaultValue: 'Свернуть' })}</span>
          )}
        </button>
      )}
    </>
  )
}

function AuthedUserBlock({
  auth,
  collapsed,
}: {
  auth: ReturnType<typeof useAuth>
  collapsed: boolean
}) {
  const { t } = useTranslation()
  const profile = auth.user?.profile
  if (!profile) return null
  const display = String(
    profile.preferred_username || profile.name || profile.email || 'user',
  )
  return (
    <div
      className={cn(
        'border-t border-line py-3 flex items-center gap-2 shrink-0',
        collapsed ? 'px-2 justify-center' : 'px-3',
      )}
      title={display}
    >
      <div className="size-8 rounded-full bg-accent text-on-accent inline-flex items-center justify-center text-cell font-semibold shrink-0">
        {display.charAt(0).toUpperCase()}
      </div>
      {!collapsed && (
        <div className="min-w-0 flex-1">
          <div className="text-cell font-medium text-ink truncate">{display}</div>
          {profile.email && (
            <div className="text-cell text-mute truncate">{String(profile.email)}</div>
          )}
        </div>
      )}
      {!collapsed && (
        <button
          type="button"
          onClick={() => auth.signoutRedirect().catch(() => auth.removeUser())}
          title={t('auth.logout', { defaultValue: 'Logout' })}
          aria-label={t('auth.logout', { defaultValue: 'Logout' })}
          className="size-7 rounded-md text-mute hover:text-ink hover:bg-surface-2 inline-flex items-center justify-center transition-colors shrink-0"
        >
          <span aria-hidden>⎋</span>
        </button>
      )}
    </div>
  )
}

function SignInCta({
  auth,
  collapsed,
}: {
  auth: ReturnType<typeof useAuth>
  collapsed: boolean
}) {
  const { t } = useTranslation()
  return (
    <button
      type="button"
      onClick={() => auth.signinRedirect()}
      className={cn(
        'border-t border-line py-2.5 text-cell text-ink-2 hover:text-ink hover:bg-surface-2 inline-flex items-center gap-2 transition-colors shrink-0',
        collapsed ? 'px-2 justify-center' : 'px-3',
      )}
      title={t('auth.login', { defaultValue: 'Войти' })}
    >
      <span aria-hidden>→</span>
      {!collapsed && t('auth.login', { defaultValue: 'Войти' })}
    </button>
  )
}

/**
 * MobileSidebar — Sheet с тем же содержимым что desktop Sidebar. Открывается
 * через hamburger button в TopBar (<1024px), закрывается на: backdrop click,
 * Escape, или клик на любой nav item (auto-close, привычная mobile UX).
 *
 * <p>Hooks logic дублируется (auth, dictsCount etc.) — нужно для filter
 * auth-required sections. Можно вынести в useSidebarSections() hook
 * следующим refactor.
 */
export function MobileSidebar({ open, onClose }: { open: boolean; onClose: () => void }) {
  const { t } = useTranslation()
  const auth = useAuth()
  const canMutate = useCanMutate()
  const canReviewSchema = useCanReviewSchema()
  const canReviewRecord = useCanReviewRecord()
  const isReviewer = canReviewSchema || canReviewRecord
  const dictsQuery = useDictionaries()
  const myDrafts = useMyDrafts(0, 1)
  const mySchemaDrafts = useMySchemaDrafts(0, 1)
  const reviews = useReviewsBadgeCount(auth.isAuthenticated)
  const outboxStats = useOutboxStats()
  const webhooks = useWebhookSubscriptions()

  const dictsCount = dictsQuery.data?.length ?? 0
  const myDraftsCount =
    (myDrafts.data?.totalElements ?? 0) + (mySchemaDrafts.data?.totalElements ?? 0)
  const reviewsCount = reviews.total
  const outboxPending = outboxStats.data?.pending ?? 0
  const webhooksActive =
    webhooks.data?.filter((w) => w.active).length ?? 0

  // Flat list per redesign — same as desktop Sidebar above.
  const sections: NavSection[] = [
    {
      items: [
        { to: '/', label: t('nav.home'), icon: Home },
        {
          to: '/dictionaries',
          label: t('nav.dictionaries'),
          icon: Database,
          badge: dictsCount > 0 ? dictsCount : undefined,
        },
        {
          to: '/my-drafts',
          label: t('nav.myDrafts'),
          icon: FileText,
          badge: myDraftsCount > 0 ? myDraftsCount : undefined,
          authRequired: true,
        },
        {
          to: '/reviews',
          label: t('nav.reviews'),
          icon: ClipboardList,
          badge: reviewsCount > 0 ? reviewsCount : undefined,
          authRequired: true,
          reviewerOnly: true,
        },
        {
          to: '/outbox',
          label: t('nav.outbox'),
          icon: Inbox,
          badge: outboxPending > 0 ? outboxPending : undefined,
          authRequired: true,
        },
        {
          to: '/webhooks',
          label: t('nav.webhooks'),
          icon: Webhook,
          badge: webhooksActive > 0 ? webhooksActive : undefined,
          authRequired: true,
        },
        { to: '/audit', label: t('nav.audit'), icon: ScrollText, authRequired: true },
        { to: '/search', label: t('nav.search'), icon: Search },
      ],
    },
  ]
  const visibleSections = sections
    .map((s) => ({
      ...s,
      items: s.items.filter((i) => {
        if (i.authRequired && !canMutate) return false
        if (i.reviewerOnly && !isReviewer) return false
        return true
      }),
    }))
    .filter((s) => s.items.length > 0)

  return (
    <Sheet open={open} onOpenChange={(v) => { if (!v) onClose() }}>
      <SheetContent
        side="left"
        size="md"
        className="!w-[260px] !max-w-[260px] !p-0 !gap-0 flex flex-col bg-surface"
      >
        <SidebarContent sections={visibleSections} auth={auth} onNavigate={onClose} />
      </SheetContent>
    </Sheet>
  )
}

function SidebarLink({
  to,
  label,
  icon: Icon,
  badge,
  onClick,
  collapsed = false,
}: NavItem & { onClick?: () => void; collapsed?: boolean }) {
  const location = useLocation()
  const active =
    to === '/'
      ? location.pathname === '/'
      : location.pathname === to || location.pathname.startsWith(to + '/')

  return (
    <Link
      to={to}
      onClick={onClick}
      title={collapsed ? (typeof label === 'string' ? label : undefined) : undefined}
      className={cn(
        // text-body = 13px workhorse per handoff (см. styles.css @utility).
        'group flex items-center rounded-md text-body transition-colors',
        collapsed ? 'justify-center h-9 mx-1' : 'gap-2.5 px-3 py-1.5',
        active
          ? 'bg-accent-bg text-accent font-medium'
          : 'text-ink-2 hover:text-ink hover:bg-surface-2',
      )}
    >
      <Icon size={collapsed ? 18 : 15} strokeWidth={1.75} className="shrink-0" />
      {!collapsed && (
        <>
          <span className="flex-1 truncate">{label}</span>
          {badge !== undefined && (
            <span
              className={cn(
                'inline-flex items-center justify-center min-w-5 h-5 px-1.5 rounded-sm text-mono',
                active
                  ? 'bg-accent text-on-accent'
                  : 'bg-surface-2 text-ink-2 group-hover:bg-line',
              )}
            >
              {badge}
            </span>
          )}
        </>
      )}
    </Link>
  )
}
