import {
  closestCenter,
  DndContext,
  type DragEndEvent,
  PointerSensor,
  useSensor,
  useSensors,
} from '@dnd-kit/core'
import {
  horizontalListSortingStrategy,
  SortableContext,
  useSortable,
} from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import { useStore } from '@nanostores/react'
import { Pin, X } from 'lucide-react'
import { TabStatusIcon } from '@/components/TabStatusIcon'
import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuTrigger,
} from '@/components/ui/context-menu'
import { cn } from '@/lib/utils'
import {
  $activeTabId,
  navigateToTab,
  onTabRemoved,
  openNewTabInProject,
} from '@/modules/stores/$navigation'
import {
  removeTab,
  reorderTabs,
  toggleTabPin,
} from '@/modules/stores/$projects'
import { $tabMeta } from '@/modules/stores/$tabMeta'
import {
  MONO_FONT,
  makeTabKey,
  resolveTabLabel,
} from '@/screens/workspace/workspace.helpers'
import type { Project, Tab } from '@/screens/workspace/workspace.types'

/* ---------------------------------------------------------------------------
 * TabItem — single sortable tab pill
 * -------------------------------------------------------------------------*/
function TabItem({ tab, projectId }: { tab: Tab; projectId: string }) {
  const activeTabsByProject = useStore($activeTabId)
  const isActive = activeTabsByProject[projectId] === tab.id
  const allTabMeta = useStore($tabMeta)
  const tabMeta = allTabMeta[makeTabKey(projectId, tab.id)]

  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({ id: tab.id })

  // Destructure role out so Biome doesn't see a static role="button" on a div,
  // but keep the rest of the a11y attributes (aria-describedby, tabIndex, etc.)
  const { role: _role, ...safeAttributes } = attributes

  function handleClose() {
    onTabRemoved(projectId, tab.id)
    removeTab(projectId, tab.id)
  }

  return (
    <ContextMenu>
      <ContextMenuTrigger className="block">
        <div
          ref={setNodeRef}
          style={{
            transform: CSS.Transform.toString(transform),
            transition,
            opacity: isDragging ? 0.5 : 1,
            zIndex: isDragging ? 50 : undefined,
          }}
          {...safeAttributes}
          {...listeners}
        >
          <div
            className={cn(
              'relative -mb-px flex h-7 min-w-[90px] items-center rounded-t-[7px] text-[11.5px] transition-colors',
              isActive
                ? 'border-[var(--tab-border)] border-t border-r border-l bg-tab-active text-tab-fg-active'
                : 'bg-transparent text-tab-fg hover:text-tab-fg-active',
            )}
          >
            {/* Navigation area — fills the pill, triggers tab switch */}
            <button
              type="button"
              className="flex flex-1 cursor-pointer items-center gap-1.5 overflow-hidden pr-1 pl-3"
              onClick={() => navigateToTab(projectId, tab.id)}
            >
              <TabStatusIcon
                tabId={makeTabKey(projectId, tab.id)}
                active={isActive}
              />
              <span className="truncate" style={{ fontFamily: MONO_FONT }}>
                {resolveTabLabel(tab, tabMeta?.cwd)}
              </span>
              {/* Danger indicator intentionally omitted here — the sidebar
                  already shows it for the same tab; duplicating it on the
                  top tab bar adds visual noise without new information. */}
            </button>

            {/* Pin / close action — sibling of nav button, not nested */}
            {tab.pinned ? (
              <button
                type="button"
                className="mr-1.5 inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded opacity-40 hover:opacity-100"
                onPointerDown={(e) => e.stopPropagation()}
                onClick={(e) => {
                  e.stopPropagation()
                  toggleTabPin(projectId, tab.id)
                }}
              >
                <Pin size={9} />
              </button>
            ) : (
              <button
                type="button"
                className="mr-1.5 inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded opacity-40 hover:bg-sidebar-hover hover:opacity-100"
                onPointerDown={(e) => e.stopPropagation()}
                onClick={(e) => {
                  e.stopPropagation()
                  handleClose()
                }}
              >
                <X size={9} />
              </button>
            )}
          </div>
        </div>
      </ContextMenuTrigger>
      <ContextMenuContent className="w-40 text-[12px]">
        <ContextMenuItem onClick={() => toggleTabPin(projectId, tab.id)}>
          {tab.pinned ? 'Unpin tab' : 'Pin tab'}
        </ContextMenuItem>
        <ContextMenuItem onClick={handleClose} className="text-destructive">
          Close tab
        </ContextMenuItem>
      </ContextMenuContent>
    </ContextMenu>
  )
}

/* ---------------------------------------------------------------------------
 * TabBar — horizontal DnD tab strip
 *
 * Layout: [scroll-container (content-sized, capped)] [add-tab button] [spacer]
 *
 * The scroll container has no flex-grow — it is sized to its content (tabs).
 * max-w: calc(100% - button-width) ensures it never pushes the "+" button
 * off-screen when tabs overflow.
 *
 * Result:
 *   Few tabs  → container is small → "+" sits right after the last tab
 *   Many tabs → container hits the cap → tabs scroll, "+" stays at the right
 *
 * The scrollbar is hidden; a right-edge gradient shadow signals overflow.
 * -------------------------------------------------------------------------*/
export function TabBar({ project }: { project: Project }) {
  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 6 } }),
  )

  const orderedTabs = [
    ...project.tabs.filter((t) => t.pinned),
    ...project.tabs.filter((t) => !t.pinned),
  ]

  function handleDragEnd(event: DragEndEvent) {
    const { active, over } = event
    if (!over || active.id === over.id) return
    const oldIdx = orderedTabs.findIndex((t) => t.id === active.id)
    const newIdx = orderedTabs.findIndex((t) => t.id === over.id)
    if (orderedTabs[oldIdx]?.pinned !== orderedTabs[newIdx]?.pinned) return
    reorderTabs(project.id, oldIdx, newIdx)
  }

  function handleAddTab() {
    openNewTabInProject(project.id)
  }

  return (
    <div
      data-tauri-drag-region
      className="flex h-[38px] shrink-0 items-end border-[var(--tab-border)] border-b bg-tab-bar px-2"
      style={{ gap: 2 }}
    >
      {/* Tab strip — content-sized, capped so the add-button is never hidden.
          `shrink-0` keeps it at content width; max-w caps it when tabs overflow. */}
      <div
        className="relative shrink-0 overflow-hidden"
        style={{ maxWidth: 'calc(100% - 1.5rem)' }}
      >
        <div
          className="flex items-end overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
          style={{ gap: 2 }}
        >
          <DndContext
            sensors={sensors}
            collisionDetection={closestCenter}
            onDragEnd={handleDragEnd}
          >
            <SortableContext
              items={orderedTabs.map((t) => t.id)}
              strategy={horizontalListSortingStrategy}
            >
              {orderedTabs.map((t) => (
                <TabItem key={t.id} tab={t} projectId={project.id} />
              ))}
            </SortableContext>
          </DndContext>
        </div>
        {/* Right-edge shadow — signals overflowing tabs */}
        <div
          className="pointer-events-none absolute top-0 right-0 bottom-0 w-8"
          style={{
            background:
              'linear-gradient(to left, var(--color-tab-bar) 20%, transparent)',
          }}
        />
      </div>

      {/* Add-tab button — flows right after the last tab when few tabs,
          sits at the right edge when the strip hits its max-width cap. */}
      <button
        type="button"
        data-tauri-drag-region={undefined}
        className="-mb-px flex h-7 w-6 shrink-0 items-center justify-center rounded text-tab-fg hover:bg-sidebar-hover hover:text-tab-fg-active"
        onClick={handleAddTab}
      >
        <svg
          width="11"
          height="11"
          viewBox="0 0 11 11"
          role="img"
          aria-label="New tab"
        >
          <path
            d="M5.5 1.5 V9.5 M1.5 5.5 H9.5"
            stroke="currentColor"
            strokeWidth="1.3"
            strokeLinecap="round"
          />
        </svg>
      </button>

      {/* Remaining space is drag region — filled by the outer data-tauri-drag-region */}
      <div className="flex-1" data-tauri-drag-region />
    </div>
  )
}
