"use client"

import { useState, useEffect, useCallback, useMemo, useRef } from "react"
import { ChevronDown, Play, Plus, Square } from "lucide-react"
import { useTranslations } from "next-intl"
import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { useActiveFolder } from "@/contexts/active-folder-context"
import { useTerminalContext } from "@/contexts/terminal-context"
import {
  bootstrapFolderCommandsFromPackageJson,
  listFolderCommands,
  terminalKill,
} from "@/lib/api"
import type { FolderCommand } from "@/lib/types"
import { CommandManageDialog } from "./command-manage-dialog"

function getSelectedCommandId(folderId: number): number | null {
  try {
    const v = localStorage.getItem(`lastCmd:${folderId}`)
    return v ? Number(v) : null
  } catch {
    return null
  }
}

function setSelectedCommandId(folderId: number, cmdId: number) {
  try {
    localStorage.setItem(`lastCmd:${folderId}`, String(cmdId))
  } catch {
    /* ignore */
  }
}

export function CommandDropdown() {
  const t = useTranslations("Folder.commandDropdown")
  const { activeFolder: folder } = useActiveFolder()
  const {
    createTerminalWithCommand,
    exitedTerminals,
    tabs: terminalTabs,
  } = useTerminalContext()
  const [commands, setCommands] = useState<FolderCommand[]>([])
  const [manageOpen, setManageOpen] = useState(false)
  const [bootstrapping, setBootstrapping] = useState(false)
  const [selectedCommandId, setSelectedCommandIdState] = useState<
    number | null
  >(null)
  const [runningCommandTerminals, setRunningCommandTerminals] = useState<
    Record<number, string>
  >({})
  const runningCommandTerminalsRef = useRef<Record<number, string>>({})

  const folderId = folder?.id ?? 0
  const folderPath = folder?.path ?? ""

  useEffect(() => {
    runningCommandTerminalsRef.current = runningCommandTerminals
  }, [runningCommandTerminals])

  // React to process exits reported by the terminal context
  useEffect(() => {
    if (exitedTerminals.size === 0) return
    setRunningCommandTerminals((prev) => {
      if (Object.keys(prev).length === 0) return prev
      let changed = false
      const next = { ...prev }
      for (const [cmdId, termId] of Object.entries(prev)) {
        if (exitedTerminals.has(termId)) {
          delete next[Number(cmdId)]
          changed = true
        }
      }
      return changed ? next : prev
    })
  }, [exitedTerminals])

  // React to terminal tabs being closed (e.g. user closes the tab directly)
  useEffect(() => {
    setRunningCommandTerminals((prev) => {
      if (Object.keys(prev).length === 0) return prev
      const tabIds = new Set(terminalTabs.map((t) => t.id))
      let changed = false
      const next = { ...prev }
      for (const [cmdId, termId] of Object.entries(prev)) {
        if (!tabIds.has(termId)) {
          delete next[Number(cmdId)]
          changed = true
        }
      }
      return changed ? next : prev
    })
  }, [terminalTabs])

  const selectCommand = useCallback(
    (commandId: number) => {
      if (!folderId) return
      setSelectedCommandId(folderId, commandId)
      setSelectedCommandIdState(commandId)
    },
    [folderId]
  )

  useEffect(() => {
    if (!folderId) {
      setSelectedCommandIdState(null)
      setRunningCommandTerminals({})
      return
    }
    setSelectedCommandIdState(getSelectedCommandId(folderId))
    setRunningCommandTerminals({})
  }, [folderId])

  const refreshCommands = useCallback(async () => {
    if (!folderId) return
    try {
      setCommands(await listFolderCommands(folderId))
    } catch (err) {
      console.error("Failed to load commands:", err)
    }
  }, [folderId])

  useEffect(() => {
    if (!folderId) return
    let ignore = false
    const loadCommands = async () => {
      try {
        setBootstrapping(false)
        const data = await listFolderCommands(folderId)
        if (ignore) return

        if (data.length > 0 || !folderPath) {
          setCommands(data)
          return
        }

        setBootstrapping(true)
        const bootstrapped = await bootstrapFolderCommandsFromPackageJson(
          folderId,
          folderPath
        )
        if (!ignore) setCommands(bootstrapped)
      } catch (err) {
        console.error("Failed to load commands:", err)
      } finally {
        if (!ignore) setBootstrapping(false)
      }
    }

    loadCommands()

    return () => {
      ignore = true
    }
  }, [folderId, folderPath])

  const runCommand = useCallback(
    async (cmd: FolderCommand) => {
      if (!folderPath) return
      if (runningCommandTerminalsRef.current[cmd.id]) return

      selectCommand(cmd.id)
      const terminalId = await createTerminalWithCommand(cmd.name, cmd.command)
      if (!terminalId) return

      setRunningCommandTerminals((prev) => ({ ...prev, [cmd.id]: terminalId }))
    },
    [createTerminalWithCommand, folderPath, selectCommand]
  )

  const stopCommand = useCallback(async (cmd: FolderCommand) => {
    const terminalId = runningCommandTerminalsRef.current[cmd.id]
    if (!terminalId) return

    setRunningCommandTerminals((prev) => {
      if (!(cmd.id in prev)) return prev
      const next = { ...prev }
      delete next[cmd.id]
      return next
    })
    try {
      await terminalKill(terminalId)
    } catch (err) {
      console.error("Failed to stop command terminal:", err)
    }
  }, [])

  const activeCmd = useMemo(
    () =>
      commands.find((c) => c.id === selectedCommandId) ?? commands[0] ?? null,
    [commands, selectedCommandId]
  )
  const activeTerminalId = activeCmd
    ? runningCommandTerminals[activeCmd.id]
    : undefined
  const isActiveCommandRunning = Boolean(activeTerminalId)

  useEffect(() => {
    if (!activeCmd && selectedCommandId !== null) {
      setSelectedCommandIdState(null)
      return
    }
    if (!activeCmd || selectedCommandId === activeCmd.id) return
    selectCommand(activeCmd.id)
  }, [activeCmd, selectedCommandId, selectCommand])

  const handleRunOrStop = useCallback(() => {
    if (!activeCmd) return
    if (isActiveCommandRunning) {
      void stopCommand(activeCmd)
      return
    }
    void runCommand(activeCmd)
  }, [activeCmd, isActiveCommandRunning, runCommand, stopCommand])

  const handleSelectCommand = useCallback(
    (cmd: FolderCommand) => {
      selectCommand(cmd.id)
    },
    [selectCommand]
  )

  if (!folder) return null

  // No commands → show add command button
  if (commands.length === 0) {
    return (
      <>
        <Button
          variant="ghost"
          size="sm"
          className="h-6 px-2 text-xs gap-1 hover:text-foreground/80"
          onClick={() => setManageOpen(true)}
          disabled={bootstrapping}
        >
          <Plus className="h-3 w-3" />
          {bootstrapping ? t("loading") : t("addCommand")}
        </Button>
        <CommandManageDialog
          open={manageOpen}
          onOpenChange={setManageOpen}
          folderId={folderId}
          commands={commands}
          onSaved={refreshCommands}
        />
      </>
    )
  }

  // Has commands → split button: [name ▼] [run/stop]
  return (
    <>
      <div className="flex items-center">
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button variant="ghost" className="h-6 hover:text-foreground/80">
              <span className="max-w-24 truncate">{activeCmd?.name}</span>
              <ChevronDown className="h-3 w-3" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end" className="min-w-56">
            {commands.map((cmd) => (
              <DropdownMenuItem
                key={cmd.id}
                onClick={() => handleSelectCommand(cmd)}
                className={`flex items-center justify-between gap-4 ${
                  cmd.id === activeCmd?.id ? "bg-accent/60" : ""
                }`}
              >
                <span className="truncate">{cmd.name}</span>
                <span className="text-xs text-muted-foreground font-mono truncate max-w-32">
                  {cmd.command}
                </span>
              </DropdownMenuItem>
            ))}
            <DropdownMenuSeparator />
            <DropdownMenuItem onClick={() => setManageOpen(true)}>
              {t("manageCommands")}
            </DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
        <Button
          variant="ghost"
          size="sm"
          className={`h-6 px-2 text-xs gap-1 ${
            isActiveCommandRunning
              ? "text-destructive hover:text-destructive"
              : "hover:text-foreground/80"
          }`}
          onClick={handleRunOrStop}
          title={
            isActiveCommandRunning
              ? t("stopCommandTitle", { command: activeCmd?.command ?? "" })
              : t("runCommandTitle", { command: activeCmd?.command ?? "" })
          }
        >
          {isActiveCommandRunning ? (
            <Square className="h-3 w-3" />
          ) : (
            <Play className="h-3 w-3" />
          )}
        </Button>
      </div>

      <CommandManageDialog
        open={manageOpen}
        onOpenChange={setManageOpen}
        folderId={folderId}
        commands={commands}
        onSaved={refreshCommands}
      />
    </>
  )
}
