import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { FiSend, FiX, FiPaperclip, FiFile, FiCornerUpLeft } from "react-icons/fi";
import type { Message } from "@/api/generated/private/models/message";
import Button from "@/components/ui/Button";
import { mediaUrl } from "@/utils/mediaUrl";

interface Props {
  disabled?: boolean;
  replyTo?: Message | null;
  onCancelReply?: () => void;
  onSend: (text: string, replyToId?: number, files?: File[]) => boolean | Promise<boolean>;
  onTyping?: (isTyping: boolean) => void;
}

export default function MessageComposer({
  disabled,
  replyTo,
  onCancelReply,
  onSend,
  onTyping,
}: Props) {
  const { t } = useTranslation("social");
  const [text, setText] = useState("");
  const [files, setFiles] = useState<File[]>([]);
  const [sending, setSending] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const typingTimerRef = useRef<number | null>(null);
  const isTypingRef = useRef(false);

  useEffect(() => {
    return () => {
      if (typingTimerRef.current) window.clearTimeout(typingTimerRef.current);
      if (isTypingRef.current) onTyping?.(false);
    };
  }, [onTyping]);

  // Revoke object URLs on unmount / file change to avoid memory leaks
  useEffect(() => {
    return () => {
      files.forEach((f) => {
        if ((f as any)._previewUrl) URL.revokeObjectURL((f as any)._previewUrl);
      });
    };
  }, [files]);

  function notifyTyping() {
    if (!isTypingRef.current) {
      isTypingRef.current = true;
      onTyping?.(true);
    }
    if (typingTimerRef.current) window.clearTimeout(typingTimerRef.current);
    typingTimerRef.current = window.setTimeout(() => {
      isTypingRef.current = false;
      onTyping?.(false);
    }, 2500);
  }

  function addFiles(incoming: FileList | null) {
    if (!incoming) return;
    const tagged = Array.from(incoming).map((f) => {
      (f as any)._previewUrl = f.type.startsWith("image/") ? URL.createObjectURL(f) : null;
      return f;
    });
    setFiles((prev) => [...prev, ...tagged].slice(0, 10)); // max 10 files
  }

  function removeFile(idx: number) {
    setFiles((prev) => {
      const next = [...prev];
      const removed = next.splice(idx, 1)[0];
      if ((removed as any)._previewUrl) URL.revokeObjectURL((removed as any)._previewUrl);
      return next;
    });
  }

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    const trimmed = text.trim();
    if (!trimmed && files.length === 0) return;
    setSending(true);
    try {
      const ok = await onSend(trimmed || "", replyTo?.id, files.length > 0 ? files : undefined);
      if (ok) {
        setText("");
        setFiles([]);
        if (isTypingRef.current) {
          isTypingRef.current = false;
          onTyping?.(false);
        }
        onCancelReply?.();
      }
    } finally {
      setSending(false);
    }
  }

  const canSend = !disabled && !sending && (text.trim().length > 0 || files.length > 0);

  return (
    <form onSubmit={handleSubmit} className="border-t border-brand-lines/15 bg-brand-bg/60 px-4 py-3">
      {replyTo && (() => {
        const replySender = replyTo.sender as { id: number; username: string; avatar: string | null } | null;
        const replyMedia = (replyTo.media_files ?? []) as unknown as { id: number; file: string; media_type: string }[];
        const firstMedia = replyMedia[0];
        return (
          <div className="mb-3 flex items-center gap-3 rounded-xl border border-brand-lines/15 bg-brand-bgLight/40 px-4 py-3">
            <FiCornerUpLeft size={18} className="shrink-0 text-brand-accent/60" />
            {firstMedia?.media_type === "IMAGE" && (
              <img
                src={mediaUrl(firstMedia.file) ?? undefined}
                className="h-14 w-14 shrink-0 rounded-lg object-cover opacity-80"
                alt=""
              />
            )}
            {firstMedia && firstMedia.media_type !== "IMAGE" && (
              <span className="shrink-0 text-xl">📎</span>
            )}
            <div className="min-w-0 flex-1">
              <p className="text-sm font-semibold text-brand-accent truncate">
                @{replySender?.username ?? "…"}
              </p>
              <p className="truncate text-sm text-brand-text/50 italic">
                {replyTo.content
                  ? replyTo.content.slice(0, 80)
                  : firstMedia
                    ? firstMedia.media_type === "IMAGE" ? "Fotka" : "Soubor"
                    : "…"}
              </p>
            </div>
            <button
              type="button"
              onClick={onCancelReply}
              className="shrink-0 rounded-full p-1.5 text-brand-text/40 hover:bg-brand-lines/10 hover:text-brand-text/80"
              aria-label={t("chat.composer.cancelReply")}
            >
              <FiX size={16} />
            </button>
          </div>
        );
      })()}

      {/* File previews */}
      {files.length > 0 && (
        <div className="mb-2 flex flex-wrap gap-2">
          {files.map((f, i) => (
            <div key={i} className="group relative shrink-0">
              {(f as any)._previewUrl ? (
                <img
                  src={(f as any)._previewUrl}
                  alt={f.name}
                  className="h-16 w-16 rounded-lg object-cover border border-brand-lines/20"
                />
              ) : (
                <div className="flex h-16 w-16 flex-col items-center justify-center gap-1 rounded-lg border border-brand-lines/20 bg-brand-bgLight/40 px-1">
                  <FiFile size={20} className="text-brand-text/50" />
                  <span className="w-full truncate text-center text-[9px] text-brand-text/50 leading-tight">{f.name}</span>
                </div>
              )}
              <button
                type="button"
                onClick={() => removeFile(i)}
                className="absolute -right-1.5 -top-1.5 flex h-4 w-4 items-center justify-center rounded-full bg-brand-bg border border-brand-lines/20 text-brand-text/60 hover:text-brand-text opacity-0 group-hover:opacity-100 transition-opacity"
              >
                <FiX size={9} />
              </button>
            </div>
          ))}
        </div>
      )}

      <div className="flex items-end gap-2">
        {/* Hidden file input */}
        <input
          ref={fileInputRef}
          type="file"
          multiple
          accept="image/*,video/*,.pdf,.doc,.docx,.zip,.txt"
          className="hidden"
          onChange={(e) => addFiles(e.target.files)}
          onClick={(e) => { (e.target as HTMLInputElement).value = ""; }}
        />
        <button
          type="button"
          onClick={() => fileInputRef.current?.click()}
          disabled={disabled || sending}
          className="flex h-[42px] w-[42px] shrink-0 items-center justify-center rounded-xl border border-brand-lines/25 bg-brand-bgLight/40 text-brand-text/60 hover:text-brand-text hover:border-brand-accent transition-colors disabled:opacity-40"
          aria-label={t("chat.composer.attach")}
        >
          <FiPaperclip size={16} />
        </button>

        <textarea
          value={text}
          onChange={(e) => { setText(e.target.value); notifyTyping(); }}
          onKeyDown={(e) => {
            if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleSubmit(e); }
          }}
          disabled={disabled || sending}
          rows={1}
          placeholder={t("chat.composer.placeholder")}
          className="min-h-[42px] max-h-40 flex-1 resize-none rounded-xl border border-brand-lines/25 bg-brand-bgLight/40 px-3 py-2 text-sm text-brand-text placeholder:text-brand-text/40 focus:outline-none focus:border-brand-accent"
        />
        <Button type="submit" disabled={!canSend} leftIcon={<FiSend size={14} />}>
          {t("common:send", { defaultValue: "Odeslat" })}
        </Button>
      </div>
    </form>
  );
}
