import { useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FiSend, FiPaperclip, FiX, FiPlay, FiFile } from "react-icons/fi";
import { useQueryClient } from "@tanstack/react-query";
import Textarea from "@/components/ui/Textarea";
import Button from "@/components/ui/Button";
import Spinner from "@/components/ui/Spinner";
import FormErrorBanner from "@/components/ui/FormErrorBanner";
import { applyServerErrors } from "@/utils/formErrors";
import { apiSocialPostsCreate } from "@/api/generated/private/posts/posts";
import { privateApi } from "@/api/privateClient";

interface Props {
  parentId?: number;
  hubId?: number | null;
  onPosted?: () => void;
}

interface ComposerForm {
  content: string;
}

export default function PostComposer({ parentId, hubId, onPosted }: Props) {
  const { t } = useTranslation("social");
  const queryClient = useQueryClient();
  const [rootError, setRootError] = useState<string | undefined>();
  const [files, setFiles] = useState<File[]>([]);
  const [previews, setPreviews] = useState<string[]>([]);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const form = useForm<ComposerForm>({
    defaultValues: { content: "" },
  });
  const { register, handleSubmit, formState, reset, watch, clearErrors } = form;
  const { errors, isSubmitting } = formState;

  const content = watch("content");

  function handleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
    const picked = Array.from(e.target.files ?? []);
    const newPreviews = picked.map((f) => URL.createObjectURL(f));
    setFiles((prev) => [...prev, ...picked]);
    setPreviews((prev) => [...prev, ...newPreviews]);
    e.target.value = "";
  }

  function removeFile(index: number) {
    URL.revokeObjectURL(previews[index]);
    setFiles((prev) => prev.filter((_, i) => i !== index));
    setPreviews((prev) => prev.filter((_, i) => i !== index));
  }

  async function onSubmit(values: ComposerForm) {
    setRootError(undefined);
    clearErrors();
    try {
      const created = await apiSocialPostsCreate({
        content: values.content,
        hub: hubId ?? null,
        reply_to: parentId ?? null,
      } as Parameters<typeof apiSocialPostsCreate>[0]);

      // Upload each file to the new post
      for (const file of files) {
        const fd = new FormData();
        fd.append("file", file);
        await privateApi.post(`/api/social/posts/${created.id}/media/`, fd);
      }

      previews.forEach((url) => URL.revokeObjectURL(url));
      setFiles([]);
      setPreviews([]);
      reset({ content: "" });
      await queryClient.invalidateQueries({ queryKey: ["social", "posts"] });
      onPosted?.();
    } catch (err) {
      setRootError(applyServerErrors(form, err));
    }
  }

  function onInvalid() {
    setRootError(undefined);
  }

  const hasContent = !!content?.trim() || files.length > 0;

  return (
    <form
      onSubmit={handleSubmit(onSubmit, onInvalid)}
      className="border-b border-brand-lines/10 px-4 py-3"
      noValidate
    >
      <FormErrorBanner message={rootError} className="mb-2" />

      <Textarea
        placeholder={
          parentId
            ? t("post.compose.replyPlaceholder")
            : t("post.compose.placeholder")
        }
        rows={3}
        disabled={isSubmitting}
        error={errors.content?.message}
        {...register("content", {
          validate: (v) => files.length > 0 || v.trim().length > 0 || true,
        })}
      />

      {/* File previews */}
      {previews.length > 0 && (
        <div className="mt-2 flex flex-wrap gap-2">
          {previews.map((src, i) => {
            const file = files[i];
            const isVideo = file?.type.startsWith("video/");
            const isImage = file?.type.startsWith("image/");
            return (
              <div key={src} className="relative">
                {isVideo ? (
                  <div className="relative h-20 w-20">
                    <video
                      src={src}
                      className="h-20 w-20 rounded-xl object-cover border border-brand-lines/20 bg-black"
                      muted
                      playsInline
                      preload="metadata"
                    />
                    <div className="absolute inset-0 flex items-center justify-center rounded-xl bg-black/30 pointer-events-none">
                      <FiPlay size={22} className="text-white drop-shadow" fill="white" />
                    </div>
                  </div>
                ) : isImage ? (
                  <img
                    src={src}
                    alt=""
                    className="h-20 w-20 rounded-xl object-cover border border-brand-lines/20"
                  />
                ) : (
                  <div className="flex h-20 w-32 flex-col items-center justify-center gap-1 rounded-xl border border-brand-lines/20 bg-brand-bgLight/40 px-2">
                    <FiFile size={22} className="text-brand-text/50 shrink-0" />
                    <span className="w-full truncate text-center text-[10px] text-brand-text/60 leading-tight">
                      {file?.name}
                    </span>
                  </div>
                )}
                <button
                  type="button"
                  onClick={() => removeFile(i)}
                  className="absolute -right-1.5 -top-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-brand-bg border border-brand-lines/30 text-brand-text/70 hover:text-brand-text shadow"
                  aria-label={t("post.compose.removeImage")}
                >
                  <FiX size={11} />
                </button>
              </div>
            );
          })}
        </div>
      )}

      <div className="mt-2 flex items-center justify-between gap-2">
        <div className="flex items-center gap-1">
          {/* Image attach button */}
          <button
            type="button"
            disabled={isSubmitting}
            onClick={() => fileInputRef.current?.click()}
            className="inline-flex items-center justify-center h-9 w-9 rounded-xl border border-brand-lines/25 bg-brand-bgLight/40 text-brand-text/60 hover:bg-brand-lines/10 hover:text-brand-accent transition-colors disabled:opacity-40"
            aria-label={t("post.compose.attachImage")}
            title={t("post.compose.attachImage")}
          >
            <FiPaperclip size={16} />
          </button>
          <input
            ref={fileInputRef}
            type="file"
            accept="*/*"
            multiple
            className="hidden"
            onChange={handleFileChange}
          />
        </div>

        <Button
          type="submit"
          disabled={isSubmitting || !hasContent}
          leftIcon={isSubmitting ? <Spinner size={14} /> : <FiSend size={14} />}
        >
          {isSubmitting
            ? t("post.compose.submitting")
            : t("post.compose.submit")}
        </Button>
      </div>
    </form>
  );
}
