import { useStore } from '@nanostores/react'
import type { CSSProperties, ReactNode, PointerEvent as ReactPointerEvent } from 'react'
import { useCallback } from 'react'

import { SidebarProvider } from '@/components/ui/sidebar'
import { triggerHaptic } from '@/lib/haptics'
import {
  $inspectorOpen,
  $sidebarOpen,
  $sidebarWidth,
  setSidebarOpen,
  setSidebarResizing,
  setSidebarWidth
} from '@/store/layout'
import { $previewTarget } from '@/store/preview'
import { $connection } from '@/store/session'

import { StatusbarControls, type StatusbarItem } from './statusbar-controls'
import { TITLEBAR_HEIGHT, titlebarControlsPosition } from './titlebar'
import { TitlebarControls, type TitlebarTool } from './titlebar-controls'

interface AppShellProps {
  children: ReactNode
  inspectorWidth: string
  leftTitlebarTools?: readonly TitlebarTool[]
  leftStatusbarItems?: readonly StatusbarItem[]
  previewWidth: string
  rightRailOpen: boolean
  sidebar: ReactNode
  statusbarItems?: readonly StatusbarItem[]
  titlebarTools?: readonly TitlebarTool[]
  onOpenSettings: () => void
  overlays?: ReactNode
}

export function AppShell({
  children,
  inspectorWidth,
  leftTitlebarTools,
  leftStatusbarItems,
  previewWidth,
  rightRailOpen,
  sidebar,
  statusbarItems,
  titlebarTools,
  onOpenSettings,
  overlays
}: AppShellProps) {
  const sidebarWidth = useStore($sidebarWidth)
  const connection = useStore($connection)
  const sidebarOpen = useStore($sidebarOpen)
  const inspectorOpen = useStore($inspectorOpen)
  const previewTarget = useStore($previewTarget)

  // The shell grid should describe visible app chrome only. Titlebar buttons
  // and draggable hit-zones are fixed overlays, so keeping an invisible grid
  // column for a closed sidebar pushes/clips the actual chat surface.
  const displayedSidebarWidth = sidebarOpen ? sidebarWidth : 0

  const titlebarControls = titlebarControlsPosition(connection?.windowButtonPosition)

  const titlebarContentInset = sidebarOpen
    ? 0
    : titlebarControls.left + TITLEBAR_HEIGHT + Math.round(TITLEBAR_HEIGHT / 2)

  const showPreviewRail = rightRailOpen && Boolean(previewTarget)
  const showInspectorRail = rightRailOpen && inspectorOpen

  const inspectorColumn = showInspectorRail ? 'var(--inspector-width)' : '0px'

  const previewColumn = showPreviewRail
    ? `min(var(--preview-width), max(0px, calc(100vw - var(--sidebar-width) - ${showInspectorRail ? 'var(--inspector-width)' : '0px'} - var(--chat-min-width))))`
    : '0px'

  const titlebarToolCount = (titlebarTools?.filter(tool => !tool.hidden).length ?? 0) + (rightRailOpen ? 1 : 0) + 2

  const shellGridColumns = 'var(--sidebar-width) minmax(0,1fr) var(--preview-col) var(--inspector-col)'

  const startSidebarResize = useCallback(
    (event: ReactPointerEvent<HTMLDivElement>) => {
      event.preventDefault()
      setSidebarResizing(true)

      const startX = event.clientX
      const startWidth = sidebarWidth
      const previousCursor = document.body.style.cursor
      const previousUserSelect = document.body.style.userSelect

      document.body.style.cursor = 'col-resize'
      document.body.style.userSelect = 'none'

      const handleMove = (moveEvent: PointerEvent) => {
        setSidebarWidth(startWidth + moveEvent.clientX - startX)
      }

      const handleUp = () => {
        setSidebarResizing(false)
        triggerHaptic('crisp')
        document.body.style.cursor = previousCursor
        document.body.style.userSelect = previousUserSelect
        window.removeEventListener('pointermove', handleMove)
        window.removeEventListener('pointerup', handleUp)
      }

      window.addEventListener('pointermove', handleMove)
      window.addEventListener('pointerup', handleUp, { once: true })
    },
    [sidebarWidth]
  )

  return (
    <SidebarProvider
      className="h-screen min-h-0 bg-background"
      onOpenChange={setSidebarOpen}
      open={sidebarOpen}
      style={
        {
          '--inspector-width': inspectorWidth,
          '--preview-width': previewWidth,
          '--sidebar-width': `${displayedSidebarWidth}px`,
          '--chat-center-offset': '0px',
          '--shell-left-sidebar-width': `${displayedSidebarWidth}px`,
          '--shell-preview-pane-width': previewColumn,
          '--shell-right-sidebar-width': inspectorColumn,
          '--shell-right-region-width': 'calc(var(--shell-preview-pane-width) + var(--shell-right-sidebar-width))',
          '--shell-preview-toolbar-gap': showPreviewRail
            ? 'max(0px, calc(var(--shell-right-sidebar-width) - (3 * var(--titlebar-control-size)) + 0.2rem))'
            : '0px',
          '--titlebar-height': `${TITLEBAR_HEIGHT}px`,
          '--titlebar-content-inset': `${titlebarContentInset}px`,
          '--titlebar-controls-left': `${titlebarControls.left}px`,
          '--titlebar-controls-top': `${titlebarControls.top}px`,
          '--titlebar-tools-right': '0.75rem',
          '--titlebar-tools-width': `calc(${titlebarToolCount} * var(--titlebar-control-size) + var(--shell-preview-toolbar-gap))`
        } as CSSProperties
      }
    >
      <TitlebarControls
        leftTools={leftTitlebarTools}
        onOpenSettings={onOpenSettings}
        showInspectorToggle={rightRailOpen}
        tools={titlebarTools}
      />

      <main
        className="relative grid h-screen w-full overflow-hidden bg-background pr-0.75 pb-0.75 pt-0.75 transition-none"
        style={
          {
            '--inspector-col': inspectorColumn,
            '--preview-col': previewColumn,
            gridTemplateColumns: shellGridColumns,
            gridTemplateRows: 'minmax(0,1fr) auto'
          } as CSSProperties
        }
      >
        <div
          aria-hidden="true"
          className="pointer-events-none absolute left-0 top-0 z-1 h-(--titlebar-height) w-(--titlebar-controls-left) [-webkit-app-region:drag]"
        />
        <div
          aria-hidden="true"
          className="pointer-events-none absolute top-0 z-1 h-(--titlebar-height) left-[calc(var(--titlebar-controls-left)+(var(--titlebar-control-size)*2)+0.75rem)] right-[calc(var(--titlebar-tools-right)+var(--titlebar-tools-width)+0.75rem)] [-webkit-app-region:drag]"
        />

        <div className="col-start-1 col-end-2 row-start-1 min-h-0 overflow-hidden">{sidebar}</div>

        {sidebarOpen && (
          <div
            aria-label="Resize sidebar"
            aria-orientation="vertical"
            className="group absolute bottom-0 top-0 left-[calc(var(--sidebar-width)-0.5rem)] z-5 w-4 cursor-col-resize [-webkit-app-region:no-drag]"
            onPointerDown={startSidebarResize}
            role="separator"
            tabIndex={0}
          >
            <span className="absolute left-1/2 top-1/2 h-23 w-0.75 -translate-x-1/2 -translate-y-1/2 rounded-full bg-muted-foreground/80 opacity-0 transition-opacity duration-100 group-hover:opacity-[0.65] group-focus-visible:opacity-[0.65]" />
          </div>
        )}

        {children}

        <StatusbarControls items={statusbarItems} leftItems={leftStatusbarItems} />
      </main>

      {overlays}
    </SidebarProvider>
  )
}
