import { useState, useRef, useCallback, useEffect, type KeyboardEvent, type ChangeEvent } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Send, Square, Paperclip, X, FileText, Image as ImageIcon, Loader2 } from "lucide-react";
import type { UploadedAttachment } from "@/hooks/use-agentscope";

const MAX_UPLOAD_BYTES = 50 * 1024 * 1024; // 50MB, matches the backend limit

interface PendingAttachment {
  id: string;
  file: File;
  status: "uploading" | "done" | "error";
  result?: UploadedAttachment;
  error?: string;
}

interface ChatInputProps {
  onSend: (text: string, attachments?: UploadedAttachment[]) => void;
  onUpload: (file: File) => Promise<UploadedAttachment | null>;
  onStop: () => void;
  isStreaming: boolean;
  isOnline: boolean;
  hasEndpoint: boolean;
  placeholder?: string;
}

export function ChatInput({
  onSend,
  onUpload,
  onStop,
  isStreaming,
  isOnline,
  hasEndpoint,
  placeholder = "Type a message...",
}: ChatInputProps) {
  const [input, setInput] = useState("");
  const [attachments, setAttachments] = useState<PendingAttachment[]>([]);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const adjustHeight = useCallback(() => {
    const textarea = textareaRef.current;
    if (!textarea) return;
    textarea.style.height = "auto";
    textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
  }, []);

  useEffect(() => {
    adjustHeight();
  }, [input, adjustHeight]);

  const isUploading = attachments.some((a) => a.status === "uploading");

  const handleFilesSelected = useCallback(
    (files: FileList | null) => {
      if (!files || files.length === 0) return;

      Array.from(files).forEach((file) => {
        if (file.size > MAX_UPLOAD_BYTES) {
          const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
          setAttachments((prev) => [
            ...prev,
            { id, file, status: "error", error: "File is over the 50MB limit" },
          ]);
          return;
        }

        const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
        setAttachments((prev) => [...prev, { id, file, status: "uploading" }]);

        onUpload(file).then((result) => {
          setAttachments((prev) =>
            prev.map((a) =>
              a.id === id
                ? result
                  ? { ...a, status: "done", result }
                  : { ...a, status: "error", error: "Upload failed" }
                : a,
            ),
          );
        });
      });
    },
    [onUpload],
  );

  const handleFileInputChange = useCallback(
    (e: ChangeEvent<HTMLInputElement>) => {
      handleFilesSelected(e.target.files);
      e.target.value = ""; // allow re-selecting the same file later
    },
    [handleFilesSelected],
  );

  const removeAttachment = useCallback((id: string) => {
    setAttachments((prev) => prev.filter((a) => a.id !== id));
  }, []);

  const handleSend = useCallback(() => {
    const readyAttachments = attachments
      .filter((a): a is PendingAttachment & { status: "done"; result: UploadedAttachment } =>
        a.status === "done" && !!a.result,
      )
      .map((a) => a.result);

    if ((!input.trim() && readyAttachments.length === 0) || isStreaming || isUploading) return;

    onSend(input.trim(), readyAttachments);
    setInput("");
    setAttachments([]);
    if (textareaRef.current) {
      textareaRef.current.style.height = "auto";
    }
  }, [input, attachments, isStreaming, isUploading, onSend]);

  const handleKeyDown = useCallback(
    (e: KeyboardEvent<HTMLTextAreaElement>) => {
      if (e.key === "Enter" && !e.shiftKey) {
        e.preventDefault();
        handleSend();
      }
    },
    [handleSend],
  );

  const isDisabled = !hasEndpoint || !isOnline;
  const canSend = (input.trim().length > 0 || attachments.some((a) => a.status === "done")) && !isUploading;

  return (
    <div className="border-t border-border bg-background/80 backdrop-blur-sm">
      <div className="max-w-3xl mx-auto px-4 py-3">
        {/* Status indicators */}
        <div className="flex items-center gap-3 mb-2 px-1">
          {!isOnline && (
            <span className="flex items-center gap-1.5 text-xs text-destructive/80">
              <span className="w-1.5 h-1.5 rounded-full bg-destructive" />
              Offline
            </span>
          )}
          {!hasEndpoint && (
            <span className="flex items-center gap-1.5 text-xs text-muted-foreground">
              <span className="w-1.5 h-1.5 rounded-full bg-muted-foreground" />
              No endpoint configured
            </span>
          )}
          {isStreaming && (
            <span className="flex items-center gap-1.5 text-xs text-muted-foreground">
              <span className="w-1.5 h-1.5 rounded-full bg-foreground/40 animate-pulse" />
              Generating...
            </span>
          )}
        </div>

        {/* Attachment previews */}
        <AnimatePresence initial={false}>
          {attachments.length > 0 && (
            <motion.div
              initial={{ opacity: 0, height: 0 }}
              animate={{ opacity: 1, height: "auto" }}
              exit={{ opacity: 0, height: 0 }}
              className="flex flex-wrap gap-2 mb-2 px-1 overflow-hidden"
            >
              {attachments.map((att) => (
                <div
                  key={att.id}
                  className={`flex items-center gap-1.5 rounded-lg border px-2 py-1.5 text-xs max-w-[220px] ${
                    att.status === "error"
                      ? "border-destructive/30 bg-destructive/5 text-destructive"
                      : "border-border bg-secondary/50 text-foreground"
                  }`}
                  title={att.status === "error" ? att.error : att.file.name}
                >
                  {att.status === "uploading" ? (
                    <Loader2 className="w-3.5 h-3.5 flex-shrink-0 animate-spin text-muted-foreground" />
                  ) : att.file.type.startsWith("image/") ? (
                    <ImageIcon className="w-3.5 h-3.5 flex-shrink-0" />
                  ) : (
                    <FileText className="w-3.5 h-3.5 flex-shrink-0" />
                  )}
                  <span className="truncate">{att.file.name}</span>
                  <button
                    onClick={() => removeAttachment(att.id)}
                    className="flex-shrink-0 text-muted-foreground hover:text-foreground transition-colors"
                    title="Remove"
                  >
                    <X className="w-3 h-3" />
                  </button>
                </div>
              ))}
            </motion.div>
          )}
        </AnimatePresence>

        {/* Input area */}
        <div className="relative flex items-end gap-2">
          <input
            ref={fileInputRef}
            type="file"
            multiple
            className="hidden"
            onChange={handleFileInputChange}
            disabled={isDisabled}
          />

          <motion.button
            whileTap={{ scale: 0.95 }}
            onClick={() => fileInputRef.current?.click()}
            disabled={isDisabled}
            className="flex-shrink-0 w-10 h-10 rounded-lg flex items-center justify-center text-muted-foreground hover:text-foreground hover:bg-secondary transition-all disabled:opacity-40 disabled:cursor-not-allowed"
            title="Attach a file (up to 50MB)"
          >
            <Paperclip className="w-4 h-4" />
          </motion.button>

          <div className="flex-1 relative">
            <textarea
              ref={textareaRef}
              value={input}
              onChange={(e) => setInput(e.target.value)}
              onKeyDown={handleKeyDown}
              placeholder={
                isDisabled
                  ? !hasEndpoint
                    ? "Configure API endpoint in Settings"
                    : "You are offline"
                  : placeholder
              }
              disabled={isDisabled}
              rows={1}
              className="w-full resize-none rounded-lg border border-border bg-secondary/50 px-4 py-3 pr-12 text-sm text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:ring-1 focus:ring-foreground/20 focus:border-foreground/30 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
            />
          </div>

          <motion.button
            whileTap={{ scale: 0.95 }}
            onClick={isStreaming ? onStop : handleSend}
            disabled={isDisabled && !isStreaming}
            className={`flex-shrink-0 w-10 h-10 rounded-lg flex items-center justify-center transition-all ${
              isStreaming
                ? "bg-destructive text-destructive-foreground hover:bg-destructive/90"
                : canSend
                  ? "bg-foreground text-background hover:bg-foreground/90"
                  : "bg-secondary text-muted-foreground cursor-not-allowed"
            }`}
            title={isStreaming ? "Stop generating" : "Send message"}
          >
            {isStreaming ? (
              <Square className="w-4 h-4 fill-current" />
            ) : (
              <Send className="w-4 h-4" />
            )}
          </motion.button>
        </div>

        {/* Hint */}
        {!isStreaming && hasEndpoint && (
          <p className="mt-1.5 text-[10px] text-muted-foreground/40 text-center">
            Press Enter to send · Shift+Enter for new line · Attach files up to 50MB
          </p>
        )}
      </div>
    </div>
  );
}
