"use client";

import Image from "next/image";
import { useCallback, useEffect, useRef, useState } from "react";
import type { QuestionField } from "@/lib/schema-adapter";
import {
  uploadTmpMedia,
  useUploadTmpMediaMutation,
} from "@/hooks/marriage/use-upload-tmp-media";
import { getApiRequestUrl } from "@/lib/http";
import { isInFlutterWebView, uploadFile } from "@/lib/webview-actions";
import { useI18n } from "@/translations/provider";
import { useQuestionAnswers } from "./question-answer-storage";
import QuestionTitle from "./question-title";
import { LoadingSkeleton } from "./loading-skeleton";

type QuestionFileProps = {
  question: QuestionField;
  disabled?: boolean;
};

const FILE_I18N: Record<
  string,
  {
    uploadPrompt: string;
    addMore: string;
    uploading: string;
    remove: string;
    uploadFailed: string;
    defaultDoc: string;
  }
> = {
  fa: {
    uploadPrompt: "بارگذاری مدارک (کارت شناسایی، پاسپورت و...)",
    addMore: "افزودن مدرک دیگر",
    uploading: "در حال آپلود در تمپ...",
    remove: "حذف مدرک",
    uploadFailed: "خطا در آپلود. لطفاً دوباره تلاش کنید.",
    defaultDoc: "مدرک",
  },
  ar: {
    uploadPrompt: "تحميل المستندات (بطاقة الهوية، جواز السفر...)",
    addMore: "إضافة مستند آخر",
    uploading: "جاري التحميل...",
    remove: "حذف المستند",
    uploadFailed: "فشل التحميل. يرجى المحاولة مرة أخرى.",
    defaultDoc: "مستند",
  },
  en: {
    uploadPrompt: "Upload documents (ID card, passport...)",
    addMore: "Add another document",
    uploading: "Uploading to temporary storage...",
    remove: "Remove document",
    uploadFailed: "Upload failed. Please try again.",
    defaultDoc: "document",
  },
  tr: {
    uploadPrompt: "Belgeleri yükleyin (Kimlik kartı, pasaport...)",
    addMore: "Başka bir belge ekle",
    uploading: "Yükleniyor...",
    remove: "Belgeyi kaldır",
    uploadFailed: "Yükleme başarısız oldu. Lütfen tekrar deneyin.",
    defaultDoc: "belge",
  },
  ur: {
    uploadPrompt: "دستاویزات اپ لوڈ کریں (شناختی کارڈ، پاسپورٹ...)",
    addMore: "ایک اور دستاویز شامل کریں",
    uploading: "اپ لوڈ ہو رہا ہے...",
    remove: "دستاویز حذف کریں",
    uploadFailed: "اپ لوڈ ناکام ہو گیا۔ براہ کرم دوبارہ کوشش کریں۔",
    defaultDoc: "دستاویز",
  },
  ru: {
    uploadPrompt: "Загрузить документы (удостоверение личности, паспорт...)",
    addMore: "Добавить еще документ",
    uploading: "Загрузка...",
    remove: "Удалить документ",
    uploadFailed: "Ошибка загрузки. Пожалуйста, попробуйте снова.",
    defaultDoc: "документ",
  },
  de: {
    uploadPrompt: "Dokumente hochladen (Personalausweis, Reisepass...)",
    addMore: "Weitere Datei hinzufügen",
    uploading: "Wird hochgeladen...",
    remove: "Dokument entfernen",
    uploadFailed: "Upload fehlgeschlagen. Bitte erneut versuchen.",
    defaultDoc: "Dokument",
  },
  fr: {
    uploadPrompt: "Télécharger des documents (carte d'identité, passeport...)",
    addMore: "Ajouter un autre document",
    uploading: "Téléchargement en cours...",
    remove: "Supprimer le document",
    uploadFailed: "Échec du téléchargement. Veuillez réessayer.",
    defaultDoc: "document",
  },
  es: {
    uploadPrompt: "Subir documentos (DNI, pasaporte...)",
    addMore: "Agregar otro documento",
    uploading: "Subiendo...",
    remove: "Eliminar documento",
    uploadFailed: "Error al subir. Inténtalo de nuevo.",
    defaultDoc: "documento",
  },
  zh: {
    uploadPrompt: "上传证件（身份证、护照等）",
    addMore: "添加其他文件",
    uploading: "上传中...",
    remove: "删除文件",
    uploadFailed: "上传失败，请重试。",
    defaultDoc: "文件",
  },
  id: {
    uploadPrompt: "Unggah dokumen (KTP, paspor...)",
    addMore: "Tambah dokumen lain",
    uploading: "Mengunggah...",
    remove: "Hapus dokumen",
    uploadFailed: "Unggah gagal. Silakan coba lagi.",
    defaultDoc: "dokumen",
  },
};

/** Map question file extensions to upload_file mediaType. */
function resolveMediaType(
  extensions: string[],
): "image" | "video" | "audio" | "file" {
  const lower = extensions.map((e) => e.replace(/^\./, "").toLowerCase());
  const allImages = lower.every((e) =>
    ["jpg", "jpeg", "png", "webp", "gif", "bmp", "svg"].includes(e),
  );
  if (allImages) return "image";

  const allVideo = lower.every((e) =>
    ["mp4", "mov", "avi", "mkv", "webm"].includes(e),
  );
  if (allVideo) return "video";

  const allAudio = lower.every((e) =>
    ["mp3", "m4a", "wav", "aac", "ogg"].includes(e),
  );
  if (allAudio) return "audio";

  return "file";
}

function isImageFile(
  fileName?: string | null,
  fileUrl?: string | null,
): boolean {
  if (
    fileUrl &&
    (fileUrl.startsWith("data:image/") || fileUrl.startsWith("blob:"))
  ) {
    if (fileUrl.startsWith("data:application/pdf")) return false;
    if (fileName && /\.(pdf|doc|docx|xls|xlsx|txt|zip|rar)$/i.test(fileName)) {
      return false;
    }
    return true;
  }
  const nameToCheck = fileName || fileUrl || "";
  return /\.(jpg|jpeg|png|webp|gif|svg|bmp|avif)$/i.test(nameToCheck);
}

export type UploadedDoc = {
  url: string;
  name: string;
  previewUrl?: string;
};

export function QuestionFile({
  question,
  disabled,
}: QuestionFileProps) {
  const { locale } = useI18n();
  const t =
    FILE_I18N[locale] ?? FILE_I18N[locale?.slice(0, 2)] ?? FILE_I18N.fa;

  const { getAnswerValue, setAnswerValue, registerPendingUpload } =
    useQuestionAnswers();
  const storedValue = getAnswerValue(question);

  const parseInitialDocs = useCallback(
    (stored: unknown): UploadedDoc[] => {
      if (!stored) return [];
      if (Array.isArray(stored)) {
        return stored
          .filter((item): item is string | Record<string, unknown> => Boolean(item))
          .map((item) => {
            if (typeof item === "string") {
              const resolvedUrl =
                item.startsWith("http") ||
                item.startsWith("blob:") ||
                item.startsWith("data:")
                  ? item
                  : getApiRequestUrl(item);
              return {
                url: item,
                previewUrl: resolvedUrl,
                name: item.split("/").pop() || t.defaultDoc,
              };
            }
            const url = (item.url || item.path || "") as string;
            const name =
              (item.name || url.split("/").pop() || t.defaultDoc) as string;
            const resolvedUrl =
              url.startsWith("http") ||
              url.startsWith("blob:") ||
              url.startsWith("data:")
                ? url
                : getApiRequestUrl(url);
            return { url, name, previewUrl: resolvedUrl };
          });
      }
      if (typeof stored === "string" && stored.trim().length > 0) {
        const resolvedUrl =
          stored.startsWith("http") ||
          stored.startsWith("blob:") ||
          stored.startsWith("data:")
            ? stored
            : getApiRequestUrl(stored);
        return [
          {
            url: stored,
            name: stored.split("/").pop() || t.defaultDoc,
            previewUrl: resolvedUrl,
          },
        ];
      }
      return [];
    },
    [t.defaultDoc],
  );

  const [uploadedDocs, setUploadedDocs] = useState<UploadedDoc[]>(() =>
    parseInitialDocs(storedValue),
  );
  const [isUploading, setIsUploading] = useState(false);
  const [uploadProgress, setUploadProgress] = useState<number | null>(null);
  const isInitiatorRef = useRef(false);
  const pendingDeferredRef = useRef<{
    resolve: (val?: any) => void;
    reject: (err?: any) => void;
  } | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  // Sync state when answers load asynchronously from server/cache
  useEffect(() => {
    if (storedValue !== undefined && storedValue !== null) {
      setUploadedDocs(parseInitialDocs(storedValue));
    }
  }, [storedValue, parseInitialDocs]);

  const acceptedFiles = (question.extras?.options ?? [])
    .map((option) => option.replace(/^\./, ""))
    .join(", ");

  const uploadTmpMediaMutation = useUploadTmpMediaMutation({
    onSuccess: (response) => {
      if (response.path) {
        const resolved = response.path.startsWith("http")
          ? response.path
          : getApiRequestUrl(response.path);
        const newDoc: UploadedDoc = {
          url: response.path,
          name: response.name ?? response.path.split("/").pop() ?? t.defaultDoc,
          previewUrl: resolved,
        };
        setUploadedDocs((prev) => {
          const nextDocs = [...prev, newDoc];
          setAnswerValue(
            question,
            nextDocs.length === 1 ? nextDocs[0].url : nextDocs.map((d) => d.url),
          );
          return nextDocs;
        });
      }
      setIsUploading(false);
      setUploadProgress(null);
    },
    onError: (error) => {
      console.error("File upload error:", error);
      setIsUploading(false);
      setUploadProgress(null);
    },
  });

  const isPending = uploadTmpMediaMutation.isPending || isUploading;

  // Listen for upload_file responses from Flutter
  useEffect(() => {
    if (!isInFlutterWebView()) return;

    const unsubscribe = window.addFlutterResponseListener?.((event) => {
      if (event.action !== "upload_file") return;
      if (event.requestId && String(event.requestId) !== String(question.id)) return;
      if (!event.requestId && !isInitiatorRef.current) return;

      switch (event.status) {
        case "picking":
          break;
        case "picked":
          setIsUploading(true);
          setUploadProgress(0);
          break;
        case "progress": {
          setIsUploading(true);
          const p = (event.data as any)?.progress;
          if (typeof p === "number") {
            setUploadProgress(Math.round(p));
          }
          break;
        }
        case "completed": {
          setIsUploading(false);
          setUploadProgress(null);
          isInitiatorRef.current = false;
          const incomingFiles = event.data?.files || [];
          const newDocs: UploadedDoc[] = [];

          for (const f of incomingFiles) {
            const remoteUrl =
              f?.path ||
              f?.url ||
              (f?.data?.path as string | undefined) ||
              (f?.data?.url as string | undefined);
            if (remoteUrl) {
              const resolved =
                remoteUrl.startsWith("http") ||
                remoteUrl.startsWith("blob:") ||
                remoteUrl.startsWith("data:")
                  ? remoteUrl
                  : getApiRequestUrl(remoteUrl);
              newDocs.push({
                url: remoteUrl,
                name: f?.name || remoteUrl.split("/").pop() || t.defaultDoc,
                previewUrl: resolved,
              });
            } else if (f?.base64) {
              const b64 = f.base64;
              fetch(b64)
                .then((res) => res.blob())
                .then((blob) => {
                  const fileObj = new File([blob], f.name ?? "document", {
                    type: blob.type,
                  });
                  uploadTmpMediaMutation.mutate(fileObj);
                });
            }
          }

          if (newDocs.length > 0) {
            setUploadedDocs((prev) => {
              const nextDocs = [...prev, ...newDocs];
              setAnswerValue(
                question,
                nextDocs.length === 1
                  ? nextDocs[0].url
                  : nextDocs.map((d) => d.url),
              );
              return nextDocs;
            });
            pendingDeferredRef.current?.resolve(newDocs);
            pendingDeferredRef.current = null;
          } else {
            pendingDeferredRef.current?.resolve([]);
            pendingDeferredRef.current = null;
          }
          break;
        }
        case "cancelled":
        case "failed":
          setIsUploading(false);
          setUploadProgress(null);
          isInitiatorRef.current = false;
          pendingDeferredRef.current?.reject(new Error("File upload failed or cancelled"));
          pendingDeferredRef.current = null;
          break;
      }
    });

    return () => {
      unsubscribe?.();
    };
  }, [question, setAnswerValue, t.defaultDoc, uploadTmpMediaMutation]);

  /** Handle file pick in Flutter WebView via upload_file action. */
  const handleFlutterPick = useCallback(() => {
    const extensions = (question.extras?.options ?? []).map((o) =>
      o.replace(/^\./, "").toLowerCase(),
    );
    const mediaType = resolveMediaType(extensions);

    isInitiatorRef.current = true;
    setIsUploading(true);

    let resolveFn!: (val?: any) => void;
    let rejectFn!: (err?: any) => void;
    const uploadPromise = new Promise((resolve, reject) => {
      resolveFn = resolve;
      rejectFn = reject;
    });
    pendingDeferredRef.current = { resolve: resolveFn, reject: rejectFn };
    registerPendingUpload?.(question.id, uploadPromise);

    const pickerSource =
      question.ui_config?.source ||
      question.ui_config?.picker_type ||
      "file_system";
    const pickerType =
      question.ui_config?.picker_type ||
      question.ui_config?.source ||
      "file_system";

    uploadFile({
      requestId: String(question.id),
      mediaType,
      multiple: true,
      source: pickerSource as any,
      picker_type: pickerType as any,
      returnAs: "upload",
      uploadUrl: `${process.env.NEXT_PUBLIC_API_BASE_URL ?? ""}/upload-tmp-media/`,
      fieldName: "file",
      allowedExtensions: extensions,
      maxBytes: 10_485_760, // 10 MB
      title:
        typeof question.title === "string" ? question.title : "Upload File",
    });
  }, [question, registerPendingUpload]);

  /** Handle file pick via browser <input type="file" multiple> (fallback). */
  function handleBrowserFileChange(files: FileList | null) {
    if (!files || files.length === 0) return;

    setIsUploading(true);
    setUploadProgress(0);

    const uploadTask = (async () => {
      const newDocs: UploadedDoc[] = [];

      for (let i = 0; i < files.length; i++) {
        const file = files[i];
        try {
          const res = await uploadTmpMedia(file, (p) => setUploadProgress(p));
          if (res.path) {
            const resolved = res.path.startsWith("http")
              ? res.path
              : getApiRequestUrl(res.path);
            newDocs.push({
              url: res.path,
              name: res.name || file.name,
              previewUrl: resolved,
            });
          }
        } catch (err) {
          console.error("Failed to upload tmp file:", file.name, err);
        }
      }

      setIsUploading(false);
      setUploadProgress(null);

      if (newDocs.length > 0) {
        setUploadedDocs((prev) => {
          const nextDocs = [...prev, ...newDocs];
          setAnswerValue(
            question,
            nextDocs.length === 1 ? nextDocs[0].url : nextDocs.map((d) => d.url),
          );
          return nextDocs;
        });
      }

      if (fileInputRef.current) {
        fileInputRef.current.value = "";
      }
    })();

    registerPendingUpload?.(question.id, uploadTask);
  }

  const handleRemoveDoc = (indexToRemove: number, e: React.MouseEvent) => {
    e.stopPropagation();
    e.preventDefault();
    setUploadedDocs((prev) => {
      const nextDocs = prev.filter((_, idx) => idx !== indexToRemove);
      if (nextDocs.length === 0) {
        setAnswerValue(question, null);
      } else if (nextDocs.length === 1) {
        setAnswerValue(question, nextDocs[0].url);
      } else {
        setAnswerValue(question, nextDocs.map((d) => d.url));
      }
      return nextDocs;
    });
  };

  const handleTriggerPick = (e?: React.MouseEvent) => {
    if (e) {
      e.stopPropagation();
    }
    if (isInFlutterWebView()) {
      handleFlutterPick();
    } else {
      fileInputRef.current?.click();
    }
  };

  const inWebView = isInFlutterWebView();
  const hasDocuments = uploadedDocs.length > 0;

  return (
    <div
      data-question-answered={hasDocuments ? "true" : "false"}
      className={[
        "flex w-full flex-col gap-2 transition-opacity duration-200",
        disabled ? "pointer-events-none opacity-30" : "",
      ].join(" ")}
    >
      <QuestionTitle question={question} />

      {/* Hidden browser input for fallback */}
      {!inWebView && (
        <input
          ref={fileInputRef}
          type="file"
          multiple
          accept={acceptedFiles ? acceptedFiles : "*/*"}
          disabled={disabled}
          onChange={(event) => handleBrowserFileChange(event.target.files)}
          className="sr-only"
        />
      )}

      <div
        role="button"
        tabIndex={0}
        onClick={!hasDocuments ? () => handleTriggerPick() : undefined}
        onKeyDown={
          !hasDocuments
            ? (e) => {
                if (e.key === "Enter" || e.key === " ") handleTriggerPick();
              }
            : undefined
        }
        className={[
          "relative flex w-full flex-col items-center justify-center rounded-[29px] border-2 border-dashed border-[#8D8D8D] bg-[#F7F7F7] text-center transition-colors duration-200 hover:border-[#6F6F6F] overflow-hidden select-none",
          hasDocuments
            ? "min-h-[156px] p-3.5"
            : "aspect-[727/330] min-h-[156px] cursor-pointer p-4",
        ].join(" ")}
      >
        {hasDocuments ? (
          /* ────── UPLOADED MULTI-DOCUMENT STATE ────── */
          <div className="relative flex w-full flex-col items-center gap-3">
            <div className="flex w-full flex-col gap-2">
              {uploadedDocs.map((doc, index) => {
                const isImg = isImageFile(doc.name, doc.previewUrl ?? doc.url);
                return (
                  <div
                    key={`${doc.url}-${index}`}
                    className="relative flex w-full items-center justify-between gap-3 rounded-[16px] border border-[#E5E7EB] bg-white p-2.5 shadow-xs transition-shadow hover:shadow-sm"
                  >
                    {/* Left: Thumbnail or PDF Icon */}
                    <div className="flex items-center gap-3 overflow-hidden">
                      {isImg && doc.previewUrl ? (
                        <img
                          src={doc.previewUrl}
                          alt={doc.name}
                          className="h-12 w-12 shrink-0 rounded-[10px] object-cover border border-[#E5E7EB]"
                        />
                      ) : (
                        <div className="relative flex h-12 w-10 shrink-0 items-center justify-center rounded-[6px] border border-[#D1D5DB] bg-[#F9FAFB] shadow-xs">
                          <svg
                            width="24"
                            height="28"
                            viewBox="0 0 32 36"
                            fill="none"
                            xmlns="http://www.w3.org/2000/svg"
                          >
                            <path
                              d="M4 0C1.79086 0 0 1.79086 0 4V32C0 34.2091 1.79086 36 4 36H28C30.2091 36 32 34.2091 32 32V10L22 0H4Z"
                              fill="#E5E7EB"
                            />
                            <path d="M22 0V10H32L22 0Z" fill="#9CA3AF" />
                          </svg>
                          <span className="absolute bottom-1 rounded-[3px] bg-[#F0445B] px-1 py-[1px] text-[7px] font-bold text-white leading-none">
                            PDF
                          </span>
                        </div>
                      )}

                      {/* Middle: File Name */}
                      <span className="truncate text-start text-xs font-semibold text-[#1F2024] max-w-[200px]">
                        {doc.name}
                      </span>
                    </div>

                    {/* Right: Individual Trash Button */}
                    <button
                      type="button"
                      onClick={(e) => handleRemoveDoc(index, e)}
                      title={t.remove}
                      className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[#F3F4F6] text-[#4B5563] transition-colors hover:bg-red-50 hover:text-[#EF4444] active:scale-95 cursor-pointer"
                    >
                      <svg
                        width="15"
                        height="15"
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        strokeWidth="2"
                        strokeLinecap="round"
                        strokeLinejoin="round"
                      >
                        <path d="M3 6h18" />
                        <path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
                        <path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
                      </svg>
                    </button>
                  </div>
                );
              })}
            </div>

            {/* Add Another Document Button */}
            <button
              type="button"
              onClick={(e) => handleTriggerPick(e)}
              className="mt-1 flex items-center justify-center gap-1.5 rounded-full border border-[#D1D5DB] bg-white px-4 py-2 text-xs font-bold text-[#374151] shadow-xs transition-colors hover:bg-[#F9FAFB] hover:border-[#9CA3AF] active:scale-98 cursor-pointer"
            >
              <svg
                width="14"
                height="14"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                strokeWidth="2.5"
                strokeLinecap="round"
                strokeLinejoin="round"
              >
                <path d="M12 5v14M5 12h14" />
              </svg>
              <span>{t.addMore}</span>
            </button>
          </div>
        ) : (
          /* ────── DEFAULT EMPTY STATE ────── */
          <div className="flex w-full flex-col items-center justify-center py-4 pointer-events-none">
            <Image
              src="/assets/images/Image.svg"
              alt="Upload"
              width={28}
              height={28}
            />
            <span className="mt-3 block group-12 leading-none font-semibold text-[#111111]">
              {t.uploadPrompt}
            </span>
            {uploadTmpMediaMutation.isError ? (
              <span className="mt-2 block group-10 leading-none font-bold text-[#D44747]">
                {t.uploadFailed}
              </span>
            ) : acceptedFiles ? (
              <span className="mt-2 block group-10 leading-none font-bold text-[#8B8B8B]">
                {acceptedFiles}
              </span>
            ) : null}
          </div>
        )}

        {/* Smooth Circular Loading Spinner Overlay with Upload Progress */}
        {isPending && (
          <div className="absolute inset-0 z-30 flex flex-col items-center justify-center rounded-[29px] bg-black/50 backdrop-blur-[1px] transition-all duration-200 gap-2">
            <div className="relative flex items-center justify-center">
              <div className="h-10 w-10 animate-spin rounded-full border-[2.5px] border-white border-t-transparent shadow-sm" />
              {uploadProgress !== null && uploadProgress > 0 && (
                <span className="absolute text-[10px] font-bold text-white leading-none">
                  {uploadProgress}%
                </span>
              )}
            </div>
            <span className="text-xs font-semibold text-white">
              {uploadProgress !== null && uploadProgress > 0
                ? `${t.uploading} (${uploadProgress}%)`
                : t.uploading}
            </span>
          </div>
        )}
      </div>
    </div>
  );
}

export default QuestionFile;
