import { useRef } from 'react';
import { Paperclip, Image, Link, FileText } from 'lucide-react';
import { toast } from '@/components/ui/sonner';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';

type AttachButtonProps = {
  /**
   * Omit when the selected model takes no images: the menu entry disappears rather than offering an
   * attachment that would be discarded before the model saw it. See `supportsImages` in InputArea.
   */
  onAttachImage?: (file: File) => void;
  onAttachWebpage: () => void;
  /** Text files are inlined into the composer rather than sent as an attachment — see below. */
  onAttachText: (text: string) => void;
  size?: 'sm' | 'md';
};

// Big enough for a config file or a stack trace, small enough that inlining it does not blow up the turn.
const MAX_TEXT_BYTES = 256 * 1024;

const TEXT_ACCEPT =
  '.txt,.md,.markdown,.json,.jsonl,.csv,.tsv,.log,.yaml,.yml,.toml,.ini,.env,.xml,.html,.css,.scss,' +
  '.js,.jsx,.ts,.tsx,.py,.rb,.go,.rs,.java,.c,.h,.cpp,.sh,.bash,.zsh,.sql,.diff,.patch,text/*';

const NUL = String.fromCharCode(0);

export function AttachButton({ onAttachImage, onAttachWebpage, onAttachText, size = 'sm' }: AttachButtonProps) {
  const imageInputRef = useRef<HTMLInputElement>(null);
  const textInputRef = useRef<HTMLInputElement>(null);

  const sizeClasses = size === 'md' ? 'h-10 w-10' : 'h-7 w-7 md:h-9 md:w-9';

  /**
   * Inlined into the composer as a fenced block rather than carried as an attachment. The attachment
   * wire format only knows `image` and `webpage`, and a text file has no representation an agent reads
   * better than the text itself — fencing it keeps the filename attached to the content, which is the
   * only thing that would otherwise be lost.
   */
  const handleTextFile = async (file: File) => {
    if (file.size > MAX_TEXT_BYTES) {
      toast.error(`${file.name} is ${Math.round(file.size / 1024)} KB — too large to inline (limit 256 KB).`);
      return;
    }
    try {
      const text = await file.text();
      // A NUL byte means this is not text, whatever the extension claimed.
      if (text.includes(NUL)) {
        toast.error(`${file.name} looks binary, not text.`);
        return;
      }
      // A longer fence when the file contains one of its own, or the block closes early and the rest of
      // the file renders as prose.
      const fence = text.includes('```') ? '````' : '```';
      onAttachText(`${fence} ${file.name}\n${text.replace(/\s+$/, '')}\n${fence}`);
    } catch (err) {
      toast.error(`Could not read ${file.name}: ${err instanceof Error ? err.message : 'unknown error'}`);
    }
  };

  return (
    <>
      <DropdownMenu>
        <DropdownMenuTrigger asChild>
          <button
            type="button"
            aria-label="Attach"
            className={`shrink-0 ${sizeClasses} flex items-center justify-center rounded-lg text-muted-foreground hover:text-foreground hover:bg-muted transition-colors cursor-pointer`}
          >
            <Paperclip className="h-4 w-4" />
          </button>
        </DropdownMenuTrigger>
        <DropdownMenuContent side="top" align="start" className="z-[800]">
          {onAttachImage && (
            <DropdownMenuItem className="cursor-pointer" onSelect={() => imageInputRef.current?.click()}>
              <Image className="mr-2 h-4 w-4" />
              Image
            </DropdownMenuItem>
          )}
          {/* "PDF" used to sit beside this one. Both were inert — no onSelect at all — so the menu offered
              four things and did two. There is no PDF text extraction anywhere in the platform, client or
              server, so that entry could not be made honest without building one first. */}
          <DropdownMenuItem className="cursor-pointer" onSelect={() => textInputRef.current?.click()}>
            <FileText className="mr-2 h-4 w-4" />
            Text File
          </DropdownMenuItem>
          <DropdownMenuItem className="cursor-pointer" onSelect={onAttachWebpage}>
            <Link className="mr-2 h-4 w-4" />
            Webpage URL
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
      <input
        ref={imageInputRef}
        type="file"
        accept="image/*"
        className="hidden"
        onChange={(ev) => {
          const file = ev.target.files?.[0];
          if (file) onAttachImage?.(file);
          ev.target.value = '';
        }}
      />
      <input
        ref={textInputRef}
        type="file"
        accept={TEXT_ACCEPT}
        className="hidden"
        onChange={(ev) => {
          const file = ev.target.files?.[0];
          if (file) handleTextFile(file);
          ev.target.value = '';
        }}
      />
    </>
  );
}
