import { cn } from "@/lib/utils";
import { ChevronDownIcon } from "lucide-react";
import { Activity, useEffect, useState } from "react";
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible";
import {
  Terminal,
  TerminalActions,
  TerminalContent,
  TerminalHeader,
  TerminalTitle,
} from "@/components/ai-elements/terminal";
import { CopyButton } from "../ui/copy-button";
import { ToggleGroup, ToggleGroupItem } from "../ui/toggle-group";
import { activityVisible } from "@/lib/activity-visible";

export const DEFAULT_TERMINAL_PROMPT = "\u001b[1;36m❯\u001b[0m";

type ActiveOutputProps = {
  value: "stdout" | "stderr";
  disabled?: boolean;
  onChange?: (value: "stdout" | "stderr") => void;
};

function ActiveOutputSwitch({ value, disabled, onChange }: ActiveOutputProps) {
  return (
    <ToggleGroup
      type="single"
      value={value}
      disabled={disabled}
      onValueChange={onChange}
      onClick={(e) => e.stopPropagation()}
    >
      <ToggleGroupItem className="h-7 px-2 text-xs font-normal" value="stdout">
        stdout
      </ToggleGroupItem>
      <ToggleGroupItem className="h-7 px-2 text-xs font-normal" value="stderr">
        stderr
      </ToggleGroupItem>
    </ToggleGroup>
  );
}

export type CollapsibleTerminalProps = {
  prompt?: string;
  input: string;
  stdout: string | null;
  stderr: string | null;
  children?: React.ReactNode;
  actions?: React.ReactNode;
  isStreaming?: boolean;
  autoScroll?: boolean;
  open?: boolean;
  onOpenChange?: (open: boolean) => void;
  defaultOpen?: boolean;
  title?: string;
  className?: string;
};

export function CollapsibleTerminal({
  prompt = DEFAULT_TERMINAL_PROMPT,
  input,
  stdout,
  stderr,
  children,
  actions,
  isStreaming = false,
  autoScroll = true,
  defaultOpen = true,
  open: controlledOpen,
  onOpenChange,
  title,
  className,
}: CollapsibleTerminalProps) {
  const isControlled = controlledOpen !== undefined;
  const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
  const open = isControlled ? controlledOpen : uncontrolledOpen;

  const [currentOutput, setCurrentOutput] = useState<"stdout" | "stderr">(
    "stdout",
  );
  const activeOutput = currentOutput === "stdout" ? stdout : stderr;
  const ansiInput = `\u001b[1;97m${input}\u001b[0m`;
  const composedOutput = `\u001b[0m${prompt} ${ansiInput}\n${activeOutput}`;

  useEffect(() => {
    if (!stdout && stderr) {
      setCurrentOutput("stderr");
    }
  }, [stdout, stderr]);

  const setOpen = (next: boolean) => {
    if (!isControlled) {
      setUncontrolledOpen(next);
    }
    onOpenChange?.(next);
  };

  return (
    <Terminal
      output={composedOutput}
      isStreaming={isStreaming}
      autoScroll={autoScroll}
      className={cn("dark", className)}
    >
      <Collapsible open={open} onOpenChange={setOpen}>
        <CollapsibleTrigger asChild>
          <TerminalHeader className="sticky top-0 z-1 cursor-pointer">
            <TerminalTitle>{title}</TerminalTitle>
            <Activity mode={activityVisible(stdout && stderr)}>
              <ActiveOutputSwitch
                value={currentOutput}
                disabled={!stdout || !stderr}
                onChange={setCurrentOutput}
              />
            </Activity>
            <TerminalActions>
              {actions}
              <CopyButton
                size="icon"
                variant="ghost"
                className="size-7 shrink-0"
                content={activeOutput ?? ""}
                onClick={(e) => e.stopPropagation()}
              />
              <ChevronDownIcon
                className={cn("size-4 transition-transform", {
                  "rotate-180": open,
                })}
              />
            </TerminalActions>
          </TerminalHeader>
        </CollapsibleTrigger>

        <CollapsibleContent>
          <TerminalContent className="shadcn-scroll selectable pt-2" />
          {children}
        </CollapsibleContent>
      </Collapsible>
    </Terminal>
  );
}
