/* eslint-disable @next/next/no-img-element */

"use client";

import useAxios from "@/hooks/useAxios";
import { optimizeImageToWebP, optimizeVideoToMp4 } from "@/lib/media";
import { createStoryBase64, StoryOverlay } from "@/api/fetchStories";
import StoryEditor from "@/components/stories/StoryEditor";
import TagUsersPicker, { TaggedUser } from "@/components/posts/TagUsersPicker";
import PostLinkPicker from "@/components/posts/PostLinkPicker";
import {
  SelectedPostLink,
} from "@/lib/postLinkCaption";
import {
  buildFullPostCaption,
  countPostCaptionLength,
  POST_CAPTION_MAX_LENGTH,
} from "@/lib/captionLength";
import PostLocationNoticeModal from "@/components/posts/PostLocationNoticeModal";
import PostExpertiseRequiredModal from "@/components/posts/PostExpertiseRequiredModal";
import VideoCoverPicker from "@/components/posts/VideoCoverPicker";
import PostImageGallery, {
  PostGalleryItem,
} from "@/components/posts/PostImageGallery";
import BoldIcon from "@/components/ui/BoldIcon";
import LocalePageShell from "@/components/i18n/LocalePageShell";
import { useUser } from "@/hooks/useUser";
import {
  userHasExpertise,
} from "@/lib/postExpertise";
import {
  hasSeenPostLocationNotice,
  markPostLocationNoticeSeen,
} from "@/lib/postLocationNotice";
import { buildStorageUrl } from "@/components/main/BaseUrl";
import { fetchPostById } from "@/api/fetchPostById";
import SelectBox from "@/components/elements/SelectBox";
import Cookies from "js-cookie";
import { useRouter, useSearchParams } from "next/navigation";
import React, { useEffect, useMemo, useState } from "react";
import toast from "react-hot-toast";
import { useTranslation } from "react-i18next";
import { ICity, IProvince, User } from "@/types/types";

type CreateMode = "image" | "video" | "story";

function fileToBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = reject;
  });
}

export default function NewPostPage() {
  const { t, i18n } = useTranslation("common");
  const captionLang = i18n.language === "en" ? "en" : "fa";
  const router = useRouter();
  const searchParams = useSearchParams();
  const { request, loading } = useAxios();
  const user = useUser();

  const editPostId = searchParams.get("edit") || "";
  const isEditMode = Boolean(editPostId);
  const initialMode = (searchParams.get("type") as CreateMode) || "image";
  const [mode, setMode] = useState<CreateMode>(
    ["image", "video", "story"].includes(initialMode) ? initialMode : "image"
  );
  const [file, setFile] = useState<File | null>(null);
  const [preview, setPreview] = useState<string>("");
  const [gallery, setGallery] = useState<PostGalleryItem[]>([]);
  const [description, setDescription] = useState("");
  const [taggedUsers, setTaggedUsers] = useState<TaggedUser[]>([]);
  const [selectedPackages, setSelectedPackages] = useState<SelectedPostLink[]>(
    []
  );
  const [selectedProjects, setSelectedProjects] = useState<SelectedPostLink[]>(
    []
  );
  const [selectedBillboards, setSelectedBillboards] = useState<
    SelectedPostLink[]
  >([]);
  const [selectedShops, setSelectedShops] = useState<SelectedPostLink[]>([]);
  const [selectedShopProducts, setSelectedShopProducts] = useState<
    SelectedPostLink[]
  >([]);
  const [selectedBooking, setSelectedBooking] = useState<SelectedPostLink[]>(
    []
  );
  const [storyOverlays, setStoryOverlays] = useState<StoryOverlay[]>([]);
  const [videoCover, setVideoCover] = useState<File | null>(null);
  const [existingVideoPath, setExistingVideoPath] = useState<string | null>(null);
  const [locationNoticeOpen, setLocationNoticeOpen] = useState(false);
  const [expertiseModalOpen, setExpertiseModalOpen] = useState(false);
  const [loadingEdit, setLoadingEdit] = useState(false);

  // شهر/استان اختیاری پست — مستقل از موقعیت پروفایل کاربر، مثل بیلبورد/پروژه
  const [provinces, setProvinces] = useState<IProvince[] | null>(null);
  const [cities, setCities] = useState<ICity[] | null>(null);
  const [provinceId, setProvinceId] = useState("");
  const [cityId, setCityId] = useState("");

  useEffect(() => {
    request<{ provinces: IProvince[] }>("GET", "/provinces")
      .then((res) => setProvinces(res?.provinces || null))
      .catch(() => {});
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (!provinceId) {
      setCities(null);
      return;
    }
    request<{ cities: ICity[] }>("GET", `/cities/${provinceId}`)
      .then((res) => setCities(res?.cities || []))
      .catch(() => {});
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [provinceId]);

  const modeLabels: Record<CreateMode, string> = useMemo(
    () => ({
      image: t("posts.modeImage"),
      video: t("posts.modeVideo"),
      story: t("posts.modeStory"),
    }),
    [t]
  );

  useEffect(() => {
    const t = searchParams.get("type") as CreateMode;
    if (!isEditMode && t && ["image", "video", "story"].includes(t)) setMode(t);
  }, [searchParams, isEditMode]);

  useEffect(() => {
    if (!editPostId) return;
    let cancelled = false;
    const load = async () => {
      setLoadingEdit(true);
      try {
        const token = Cookies.get("token") || "";
        const post = await fetchPostById(editPostId, token);
        if (cancelled || !post) return;
        setMode(post.type === "video" ? "video" : "image");
        setDescription(post.caption || "");
        const imageFiles = (post.files || []).filter((f) => f.type !== "video");
        const videoFile = (post.files || []).find((f) => f.type === "video");
        if (post.type === "video" && videoFile?.path) {
          setPreview(buildStorageUrl(videoFile.path));
          setFile(null);
          setExistingVideoPath(videoFile.path);
          const cover = imageFiles[0];
          if (cover?.path) {
            setGallery([
              {
                id: `ex-${cover.path}`,
                preview: buildStorageUrl(cover.path),
                existingPath: cover.path,
              },
            ]);
          }
        } else {
          setExistingVideoPath(null);
          setGallery(
            (post.files || [])
              .filter((f) => f.path)
              .map((f) => ({
                id: `ex-${f.path}`,
                preview: buildStorageUrl(f.path),
                existingPath: f.path,
              }))
          );
          const first = post.files?.[0];
          if (first?.path) {
            setPreview(buildStorageUrl(first.path));
          }
        }
      } catch {
        toast.error(t("posts.uploadError"));
        router.replace("/");
      } finally {
        if (!cancelled) setLoadingEdit(false);
      }
    };
    void load();
    return () => {
      cancelled = true;
    };
  }, [editPostId, router, t]);

  const resetMedia = () => {
    if (preview?.startsWith("blob:")) URL.revokeObjectURL(preview);
    gallery.forEach((item) => {
      if (item.preview?.startsWith("blob:")) URL.revokeObjectURL(item.preview);
    });
    setFile(null);
    setPreview("");
    setGallery([]);
    setStoryOverlays([]);
    setVideoCover(null);
  };

  const switchMode = (next: CreateMode) => {
    if (isEditMode) return;
    resetMedia();
    setMode(next);
  };

  const acceptAttr = useMemo(() => {
    if (mode === "video" || mode === "story") return "video/*,image/*";
    return "image/*";
  }, [mode]);

  const onPickMain = (e: React.ChangeEvent<HTMLInputElement>) => {
    const picked = e.target.files?.[0];
    if (!picked) return;

    if (mode === "video" && !picked.type.startsWith("video/")) {
      toast.error(t("posts.videoOnly"));
      return;
    }
    if (mode === "image" && !picked.type.startsWith("image/")) {
      toast.error(t("posts.imageOnly"));
      return;
    }

    if (mode === "image") {
      const item: PostGalleryItem = {
        id: `new-${Date.now()}`,
        file: picked,
        preview: URL.createObjectURL(picked),
      };
      setGallery((prev) => {
        if (!prev.length) {
          setPreview(item.preview);
          setFile(picked);
          return [item];
        }
        return [...prev, item].slice(0, 10);
      });
      return;
    }

    if (preview?.startsWith("blob:")) URL.revokeObjectURL(preview);
    setFile(picked);
    setPreview(URL.createObjectURL(picked));
    if (mode === "video") setVideoCover(null);
  };

  const returnPath = useMemo(() => {
    const params = new URLSearchParams();
    if (mode !== "image") params.set("type", mode);
    const qs = params.toString();
    return qs ? `/new-post?${qs}` : "/new-post";
  }, [mode]);

  const resolveProfileExpertise = async (): Promise<User | undefined> => {
    if (userHasExpertise(user)) return user;
    try {
      const response = await request<{ user: User }>(
        "GET",
        "/profile",
        null,
        { noToast: true }
      );
      return response?.user;
    } catch {
      return user;
    }
  };

  const ensurePostExpertise = async (): Promise<boolean> => {
    const profile = await resolveProfileExpertise();
    if (userHasExpertise(profile)) return true;
    toast.error(t("posts.expertiseRequired"));
    setExpertiseModalOpen(true);
    return false;
  };

  const publish = async () => {
    const token = Cookies.get("token");
    if (!token) {
      toast.error(t("posts.loginToPost"));
      return;
    }

    if (mode === "story") {
      if (!file) {
        toast.error(t("posts.storyMediaRequired"));
        return;
      }
      try {
        toast.loading(t("posts.publishingStory"), { id: "story-upload" });
        let optimized: File;
        if (file.type.startsWith("video/")) {
          // اگر تبدیل ویدیو (ffmpeg) در دسترس نبود، فایل اصلی ارسال می‌شود
          try {
            optimized = await optimizeVideoToMp4(file);
          } catch {
            optimized = file;
          }
        } else {
          try {
            optimized = await optimizeImageToWebP(file);
          } catch {
            optimized = file;
          }
        }
        await createStoryBase64(
          {
            name: optimized.name,
            type: optimized.type,
            data: await fileToBase64(optimized),
          },
          token,
          storyOverlays
        );
        toast.success(t("posts.storyPublished"), { id: "story-upload" });
        router.push("/");
      } catch (err) {
        toast.error(err instanceof Error ? err.message : t("posts.storyPublishError"), {
          id: "story-upload",
        });
      }
      return;
    }

    if (!(await ensurePostExpertise())) {
      return;
    }

    const caption = buildFullPostCaption(
      description,
      taggedUsers,
      selectedPackages,
      selectedProjects,
      selectedBillboards,
      captionLang,
      selectedShops,
      selectedShopProducts,
      selectedBooking
    );

    if (caption.length > POST_CAPTION_MAX_LENGTH) {
      toast.error(
        t("posts.captionTooLong", { max: POST_CAPTION_MAX_LENGTH }),
        {
          id: "post-upload",
        }
      );
      return;
    }

    try {
      toast.loading(t("posts.uploading"), { id: "post-upload" });

      if (isEditMode) {
        const keep_files = [
          ...gallery
            .filter((g) => g.existingPath)
            .map((g) => ({ path: g.existingPath!, type: "image" as const })),
          ...(mode === "video" && existingVideoPath && !file
            ? [{ path: existingVideoPath, type: "video" as const }]
            : []),
        ];
        const newGalleryFiles = gallery
          .filter((g) => g.file)
          .map((g) => g.file!) as File[];
        const videoFiles =
          mode === "video" && file
            ? ([...(videoCover ? [videoCover] : []), file] as File[])
            : mode === "video" && videoCover
              ? [videoCover]
              : [];
        const uploadFiles =
          mode === "video" ? videoFiles : newGalleryFiles;

        if (!keep_files.length && !uploadFiles.length) {
          toast.error(t("posts.mediaRequired"), { id: "post-upload" });
          return;
        }

        const optimizedFiles = await Promise.all(
          uploadFiles.map(async (f) =>
            f.type.startsWith("video/")
              ? optimizeVideoToMp4(f)
              : optimizeImageToWebP(f)
          )
        );
        const filesBase64 = await Promise.all(
          optimizedFiles.map(async (f) => ({
            name: f.name,
            type: f.type,
            data: await fileToBase64(f),
          }))
        );

        let media_order: string[] = [];
        if (mode === "image") {
          let newIdx = 0;
          let keepIdx = 0;
          media_order = gallery.map((g) => {
            if (g.existingPath) return `existing:${keepIdx++}`;
            return `new:${newIdx++}`;
          });
        } else {
          media_order = [
            ...keep_files.map((_, i) => `existing:${i}`),
            ...filesBase64.map((_, i) => `new:${i}`),
          ];
        }

        await request(
          "POST",
          `/posts/${editPostId}/update-base64`,
          {
            postId: editPostId,
            files: filesBase64,
            caption,
            tagged_user_ids: taggedUsers.map((u) => u._id),
            keep_files,
            media_order,
          },
          { noToast: true }
        );
        toast.success(t("posts.postUpdated"), { id: "post-upload" });
        router.push(`/posts/${editPostId}`);
        return;
      }

      const imageFiles =
        mode === "image"
          ? ((gallery.length
              ? gallery.map((g) => g.file).filter(Boolean)
              : file
                ? [file]
                : []) as File[])
          : mode === "video" && file
            ? ([...(videoCover ? [videoCover] : []), file] as File[])
            : file
              ? [file]
              : [];

      if (!imageFiles.length) {
        toast.error(t("posts.mediaRequired"), { id: "post-upload" });
        return;
      }

      const optimizedFiles = await Promise.all(
        imageFiles.map(async (f) =>
          f.type.startsWith("video/")
            ? optimizeVideoToMp4(f)
            : optimizeImageToWebP(f)
        )
      );
      const filesBase64 = await Promise.all(
        optimizedFiles.map(async (f) => ({
          name: f.name,
          type: f.type,
          data: await fileToBase64(f),
        }))
      );

      await request("POST", "/posts/create-base64", {
        files: filesBase64,
        caption,
        tagged_user_ids: taggedUsers.map((u) => u._id),
        linked_course_id: selectedPackages[0]?._id ?? null,
        linked_project_id: selectedProjects[0]?._id ?? null,
        linked_billboard_id: selectedBillboards[0]?._id ?? null,
        linked_shop_id: selectedShops[0]?._id ?? null,
        linked_shop_product_id: selectedShopProducts[0]?._id ?? null,
        linked_booking_id: selectedBooking[0]?._id ?? null,
        province_id: provinceId || null,
        city_id: cityId || null,
      }, { noToast: true });
      toast.success(t("posts.postPublished"), { id: "post-upload" });
      router.push("/");
    } catch (err: unknown) {
      const axiosErr = err as {
        response?: { data?: { type?: string; message?: string } };
      };
      if (axiosErr.response?.data?.type === "expertise_required") {
        toast.error(
          axiosErr.response.data.message || t("posts.expertiseRequired"),
          { id: "post-upload" }
        );
        setExpertiseModalOpen(true);
        return;
      }
      toast.error(err instanceof Error ? err.message : t("posts.uploadError"), {
        id: "post-upload",
      });
    }
  };

  const locationSharingEnabled = user?.post_location_enabled === true;

  const handleShareClick = async () => {
    if (!isStory && !(await ensurePostExpertise())) {
      return;
    }

    if (
      !isStory &&
      locationSharingEnabled &&
      !hasSeenPostLocationNotice()
    ) {
      setLocationNoticeOpen(true);
      return;
    }
    void publish();
  };

  const dismissLocationNotice = () => {
    markPostLocationNoticeSeen();
    setLocationNoticeOpen(false);
  };

  const captionLength = countPostCaptionLength(
    description,
    taggedUsers,
    selectedPackages,
    selectedProjects,
    selectedBillboards,
    captionLang,
    selectedShops,
    selectedShopProducts,
    selectedBooking
  );

  const isStory = mode === "story";

  return (
    <LocalePageShell>
    <div className="mx-auto flex min-h-[calc(100dvh-8rem)] max-w-lg flex-col bg-background">
      {/* Header — Instagram style */}
      <header className="sticky top-0 z-10 flex items-center justify-between border-b border-neutral-200 px-4 py-3 dark:border-neutral-800">
        <button
          type="button"
          onClick={() => router.back()}
          className="flex h-9 w-9 items-center justify-center"
          aria-label={t("common.back")}
        >
          <BoldIcon name="arrow-right-3" size={22} className="block dark:invert" />
        </button>
        <span className="text-base font-semibold">
          {isEditMode
            ? t("posts.editPostTitle")
            : isStory
              ? t("posts.newStory")
              : t("posts.newPost")}
        </span>
        <button
          type="button"
          onClick={handleShareClick}
          disabled={loading || loadingEdit}
          className="text-sm font-semibold text-[#0095f6] disabled:opacity-40"
        >
          {loading || loadingEdit ? "…" : t("posts.shareButton")}
        </button>
      </header>

      {/* Mode tabs */}
      {!isEditMode ? (
      <div className="flex border-b border-neutral-200 dark:border-neutral-800">
        {(["image", "video", "story"] as CreateMode[]).map((m) => (
          <button
            key={m}
            type="button"
            onClick={() => switchMode(m)}
            className={`flex-1 py-3 text-sm font-semibold transition ${
              mode === m
                ? "border-b-2 border-neutral-900 text-neutral-900 dark:border-white dark:text-white"
                : "text-neutral-400"
            }`}
          >
            {modeLabels[m]}
          </button>
        ))}
      </div>
      ) : null}

      {/* Story editor (media + draggable text) */}
      {isStory && preview && file ? (
        <div className="flex flex-col gap-3 p-4">
          <StoryEditor
            mediaUrl={preview}
            mediaType={file.type.startsWith("video/") ? "video" : "image"}
            overlays={storyOverlays}
            onChange={setStoryOverlays}
          />
          <label className="mx-auto rounded-lg bg-neutral-100 px-4 py-2 text-center text-xs text-neutral-600 dark:bg-neutral-800 dark:text-neutral-300">
            {t("posts.changeFile")}
            <input
              type="file"
              accept={acceptAttr}
              className="hidden"
              onChange={onPickMain}
            />
          </label>
        </div>
      ) : (
      /* Media area */
      <div
        className={`relative flex flex-1 flex-col items-center justify-center bg-neutral-100 dark:bg-neutral-950 ${
          isStory ? "aspect-[9/16] max-h-[55vh]" : "min-h-[280px]"
        }`}
      >
        {preview ? (
          <>
            {file?.type.startsWith("video/") ? (
              <video
                src={preview}
                className="max-h-[55vh] w-full object-contain"
                controls
                playsInline
              />
            ) : (
              <img
                src={preview}
                alt="preview"
                className={`w-full object-contain ${isStory ? "max-h-[55vh]" : "max-h-[360px]"}`}
              />
            )}
            <button
              type="button"
              onClick={resetMedia}
              className="absolute left-3 top-3 rounded-full bg-black/50 p-2"
            >
              <BoldIcon name="close-circle" size={20} tinted className="text-white" />
            </button>
          </>
        ) : (
          <label className="flex cursor-pointer flex-col items-center gap-3 p-8 text-neutral-500">
            <BoldIcon name="gallery-add" size={48} className="block opacity-60 dark:invert" />
            <span className="text-sm">
              {isStory
                ? t("posts.pickStoryMedia")
                : mode === "video"
                  ? t("posts.pickVideo")
                  : t("posts.pickImage")}
            </span>
            <span className="rounded-lg bg-[#0095f6] px-4 py-2 text-sm font-semibold text-white">
              {t("posts.pickFromGallery")}
            </span>
            <input
              type="file"
              accept={acceptAttr}
              className="hidden"
              onChange={onPickMain}
            />
          </label>
        )}
        {preview && (
          <label className="absolute bottom-4 rounded-lg bg-black/60 px-4 py-2 text-xs text-white">
            {t("posts.changeFile")}
            <input type="file" accept={acceptAttr} className="hidden" onChange={onPickMain} />
          </label>
        )}
      </div>
      )}

      {/* Extra images for photo post — reorder / delete */}
      {mode === "image" && !isStory ? (
        <PostImageGallery
          items={gallery}
          onChange={(items) => {
            setGallery(items);
            const first = items[0];
            setPreview(first?.preview || "");
            setFile(first?.file || null);
          }}
        />
      ) : null}

      {mode === "video" && preview && (file || existingVideoPath) ? (
        <VideoCoverPicker
          videoUrl={preview}
          onCoverChange={setVideoCover}
          initialCoverUrl={
            gallery.find((item) => item.existingPath && !item.file)?.preview
          }
        />
      ) : null}

      {/* Caption — not for story */}
      {!isStory && (
        <div className="space-y-3 border-t border-neutral-200 p-4 dark:border-neutral-800">
          <textarea
            placeholder={t("posts.captionPlaceholder")}
            value={description}
            onChange={(e) => setDescription(e.target.value)}
            rows={5}
            className="min-h-[7.5rem] w-full resize-none whitespace-pre-wrap bg-transparent text-sm outline-none placeholder:text-neutral-400"
          />
          <div className="flex justify-between text-xs text-neutral-400">
            <span>
              {captionLength}/{POST_CAPTION_MAX_LENGTH}
            </span>
          </div>
          <TagUsersPicker selected={taggedUsers} onChange={setTaggedUsers} max={50} />
          <PostLinkPicker
            selectedPackages={selectedPackages}
            selectedProjects={selectedProjects}
            selectedBillboards={selectedBillboards}
            selectedShops={selectedShops}
            selectedShopProducts={selectedShopProducts}
            selectedBooking={selectedBooking}
            onPackagesChange={setSelectedPackages}
            onProjectsChange={setSelectedProjects}
            onBillboardsChange={setSelectedBillboards}
            onShopsChange={setSelectedShops}
            onShopProductsChange={setSelectedShopProducts}
            onBookingChange={setSelectedBooking}
          />

          <div className="mt-4 flex items-center gap-2">
            <SelectBox
              value={provinceId}
              onChange={(e) => {
                setProvinceId(e.target.value);
                setCityId("");
              }}
            >
              <option value="">{t("posts.provinceOptional")}</option>
              {provinces?.map((item) => (
                <option key={item.id} value={item.id}>
                  {item.name}
                </option>
              ))}
            </SelectBox>
            <SelectBox
              value={cityId}
              onChange={(e) => setCityId(e.target.value)}
              disabled={!provinceId}
            >
              <option value="">{t("posts.cityOptional")}</option>
              {cities?.map((item) => (
                <option key={item.id} value={item.id}>
                  {item.name}
                </option>
              ))}
            </SelectBox>
          </div>
        </div>
      )}

      {isStory && (
        <p className="px-4 pb-6 text-center text-xs text-neutral-500">
          {t("posts.storyExpiryHint")}
        </p>
      )}

      <PostLocationNoticeModal
        isOpen={locationNoticeOpen}
        onNo={() => {
          dismissLocationNotice();
          void publish();
        }}
        onYes={dismissLocationNotice}
      />

      <PostExpertiseRequiredModal
        isOpen={expertiseModalOpen}
        onClose={() => setExpertiseModalOpen(false)}
        returnPath={returnPath}
      />
    </div>
    </LocalePageShell>
  );
}
