import { useStore } from '@nanostores/react'

import { Button } from '@/components/ui/button'
import { FadeText } from '@/components/ui/fade-text'
import { FolderOpen, RefreshCw } from '@/lib/icons'
import { normalizeOrLocalPreviewTarget } from '@/lib/local-preview'
import { cn } from '@/lib/utils'
import { notifyError } from '@/store/notifications'
import { setCurrentSessionPreviewTarget } from '@/store/preview'
import { $currentCwd } from '@/store/session'

import { SidebarPanelLabel } from '../shell/sidebar-label'
import { ProjectTree } from './tree'
import { useProjectTree } from './use-project-tree'

interface FileBrowserPaneProps {
  /** Activates a file row — drops the path into the composer as `@file:` ref. */
  onActivateFile: (path: string) => void
  onChangeCwd: (path: string) => Promise<void> | void
}

export function FileBrowserPane({ onActivateFile, onChangeCwd }: FileBrowserPaneProps) {
  const currentCwd = useStore($currentCwd).trim()
  const hasCwd = currentCwd.length > 0

  const cwdName = hasCwd
    ? (currentCwd
        .split(/[\\/]+/)
        .filter(Boolean)
        .pop() ?? currentCwd)
    : 'No folder selected'

  const { data, loadChildren, openState, refreshRoot, rootError, rootLoading, setNodeOpen } = useProjectTree(currentCwd)

  const chooseFolder = async () => {
    const selected = await window.hermesDesktop?.selectPaths({
      title: 'Change working directory',
      defaultPath: hasCwd ? currentCwd : undefined,
      directories: true,
      multiple: false
    })

    if (selected?.[0]) {
      await onChangeCwd(selected[0])
    }
  }

  const previewFile = async (path: string) => {
    try {
      const preview = await normalizeOrLocalPreviewTarget(path, currentCwd || undefined)

      if (!preview) {
        throw new Error(`Could not preview ${path}`)
      }

      setCurrentSessionPreviewTarget(preview, 'file-browser', path)
    } catch (error) {
      notifyError(error, 'Preview unavailable')
    }
  }

  return (
    <aside
      aria-label="File browser"
      className="relative flex h-full w-full min-w-0 flex-col overflow-hidden border-l border-border/60 bg-[color-mix(in_srgb,var(--dt-sidebar-bg)_94%,transparent)] px-(--sidebar-content-inline-padding) pt-[calc(var(--titlebar-height)-0.625rem)] text-muted-foreground [backdrop-filter:blur(1.5rem)_saturate(1.08)]"
    >
      <header className="group/project-header shrink-0 pb-1 pt-0">
        <div className="flex items-center gap-1.5">
          <FadeText
            className="flex flex-1 items-center px-2 pb-1 pt-1"
            title={hasCwd ? currentCwd : 'No folder selected'}
          >
            <SidebarPanelLabel>{cwdName}</SidebarPanelLabel>
          </FadeText>
          <Button
            aria-label="Change working directory"
            className="pointer-events-none size-6 shrink-0 text-muted-foreground/75 opacity-0 transition-opacity hover:text-foreground focus-visible:opacity-100 group-focus-within/project-header:pointer-events-auto group-focus-within/project-header:opacity-100 group-hover/project-header:pointer-events-auto group-hover/project-header:opacity-100"
            onClick={() => void chooseFolder()}
            size="icon"
            title="Change working directory"
            variant="ghost"
          >
            <FolderOpen className="size-3.5" />
          </Button>
          <Button
            aria-label="Refresh tree"
            className="pointer-events-none size-6 shrink-0 text-muted-foreground/75 opacity-0 transition-opacity hover:text-foreground focus-visible:opacity-100 group-focus-within/project-header:pointer-events-auto group-focus-within/project-header:opacity-100 group-hover/project-header:pointer-events-auto group-hover/project-header:opacity-100"
            disabled={!hasCwd || rootLoading}
            onClick={() => void refreshRoot()}
            size="icon"
            title="Refresh tree"
            variant="ghost"
          >
            <RefreshCw className={cn('size-3.5', rootLoading && 'animate-spin')} />
          </Button>
        </div>
      </header>

      <FileTreeBody
        cwd={currentCwd}
        data={data}
        error={rootError}
        loading={rootLoading}
        onActivateFile={onActivateFile}
        onLoadChildren={loadChildren}
        onNodeOpenChange={setNodeOpen}
        onPreviewFile={previewFile}
        openState={openState}
      />
    </aside>
  )
}

interface FileTreeBodyProps {
  cwd: string
  data: ReturnType<typeof useProjectTree>['data']
  error: string | null
  loading: boolean
  onActivateFile: (path: string) => void
  onLoadChildren: (id: string) => void | Promise<void>
  onNodeOpenChange: (id: string, open: boolean) => void
  onPreviewFile?: (path: string) => void
  openState: ReturnType<typeof useProjectTree>['openState']
}

function FileTreeBody({
  cwd,
  data,
  error,
  loading,
  onActivateFile,
  onLoadChildren,
  onNodeOpenChange,
  onPreviewFile,
  openState
}: FileTreeBodyProps) {
  if (!cwd) {
    return <EmptyState body="Set a working directory from the status bar to browse files." title="No project" />
  }

  if (error) {
    return <EmptyState body={`Could not read this folder (${error}).`} title="Unreadable" />
  }

  if (loading && data.length === 0) {
    return <EmptyState body="Reading project…" title="Loading" />
  }

  if (data.length === 0) {
    return <EmptyState body="This folder is empty." title="Empty" />
  }

  return (
    <ProjectTree
      data={data}
      onActivateFile={onActivateFile}
      onLoadChildren={onLoadChildren}
      onNodeOpenChange={onNodeOpenChange}
      onPreviewFile={onPreviewFile}
      openState={openState}
    />
  )
}

function EmptyState({ body, title }: { body: string; title: string }) {
  return (
    <div className="flex min-h-0 flex-1 flex-col items-center justify-center gap-1 px-4 text-center">
      <div className="text-[0.7rem] font-semibold uppercase tracking-[0.07em] text-muted-foreground/75">{title}</div>
      <div className="text-[0.68rem] leading-relaxed text-muted-foreground/65">{body}</div>
    </div>
  )
}
