"use client";

import { useTranslation } from "@/hooks/useTranslation";
import { getReview, submitReview, updateReview } from "@/libs/axios/modules/review";
import { getGoldFlea, postGoldFlea } from "@/libs/axios/modules/reward";
import { PostModel, ReviewModel, TransactionModel } from "@/models";
import { withSlug } from "@/utils/slug";
import { format } from "date-fns";
import { AnimatePresence, motion } from "framer-motion";
import { Coins, Pencil, Star, X } from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "react-toastify";

function initialName(name: string) {
    if (!name) return "?";
    return name.split(" ").slice(0, 2).map((w) => w[0]).join("").toUpperCase();
}

function StarDisplay({ value, size = 14 }: { value: number; size?: number }) {
    return (
        <div className="flex items-center gap-0.5">
            {Array.from({ length: 5 }).map((_, i) => (
                <Star
                    key={i}
                    style={{ width: size, height: size }}
                    className={i < value ? "fill-yellow-400 text-yellow-400" : "text-slate-200 fill-slate-200"}
                />
            ))}
        </div>
    );
}

function StarInput({ value, onChange }: { value: number; onChange: (v: number) => void }) {
    const [hovered, setHovered] = useState(0);
    return (
        <div className="flex items-center gap-1">
            {Array.from({ length: 5 }).map((_, i) => (
                <button
                    key={i}
                    type="button"
                    onMouseEnter={() => setHovered(i + 1)}
                    onMouseLeave={() => setHovered(0)}
                    onClick={() => onChange(i + 1)}
                    className="cursor-pointer transition-transform hover:scale-110"
                >
                    <Star
                        className={`w-9 h-9 transition-colors ${i < (hovered || value)
                            ? "fill-yellow-400 text-yellow-400"
                            : "text-slate-200 fill-slate-200"
                            }`}
                    />
                </button>
            ))}
        </div>
    );
}

function Avatar({ avatar, name, size = "w-8 h-8" }: { avatar?: string; name: string; size?: string }) {
    return avatar ? (
        <img src={avatar} alt={name} className={`${size} rounded-full object-cover shrink-0`} />
    ) : (
        <div className={`${size} rounded-full bg-primary-500 flex items-center justify-center shrink-0`}>
            <span className="text-[10px] font-bold text-white">{initialName(name)}</span>
        </div>
    );
}

function ReviewModal({
    open,
    novelTitle,
    existing,
    novelId,
    token,
    onSuccess,
    onClose,
}: {
    open: boolean;
    novelTitle: string;
    existing?: ReviewModel;
    novelId: string;
    token?: string;
    onSuccess: () => void;
    onClose: () => void;
}) {
    const { t } = useTranslation();
    const [rating, setRating] = useState(existing?.value ?? 0);
    const [text, setText] = useState(existing?.text ?? "");
    const [loading, setLoading] = useState(false);

    useEffect(() => {
        if (open) { setRating(existing?.value ?? 0); setText(existing?.text ?? ""); }
    }, [open, existing]);

    useEffect(() => {
        document.body.style.overflow = open ? "hidden" : "";
        return () => { document.body.style.overflow = ""; };
    }, [open]);

    const onSubmit = async () => {
        if (!token) { toast.error(t("you need to login first")); return; }
        if (!rating) { toast.error("Pilih rating terlebih dahulu"); return; }
        setLoading(true);
        try {
            if (existing) {
                await updateReview(token, { id: novelId, review_id: existing.id, text, value: rating });
            } else {
                await submitReview(token, { id: novelId, text, value: rating });
            }
            toast.success(t("success.submit"));
            onSuccess();
            onClose();
        } catch (err: any) {
            toast.error(err?.data?.message ?? err?.message ?? "Terjadi kesalahan");
        } finally {
            setLoading(false);
        }
    };

    return (
        <AnimatePresence>
            {open && (
                <>
                    <motion.div
                        className="fixed inset-0 z-9999 bg-black/40 backdrop-blur-sm"
                        onClick={onClose}
                        initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
                    />
                    <div className="fixed inset-0 z-10000 flex items-end md:items-center justify-center">
                        <motion.div
                            className="bg-white w-full md:max-w-md md:rounded-3xl rounded-t-3xl overflow-hidden shadow-xl"
                            initial={{ y: "100%" }} animate={{ y: 0 }} exit={{ y: "100%" }}
                            transition={{ type: "spring", stiffness: 300, damping: 30 }}
                        >
                            <div className="flex items-center justify-between px-6 pt-5 pb-3">
                                <p className="font-semibold text-lg text-slate-800 capitalize">{t("leave review")}</p>
                                <button onClick={onClose} className="w-8 h-8 flex items-center justify-center rounded-xl hover:bg-slate-100 cursor-pointer transition-colors">
                                    <X className="w-4 h-4 text-slate-500" />
                                </button>
                            </div>

                            <div className="px-6 pb-6 flex flex-col gap-5">
                                <div className="text-center">
                                    <p className="text-xs text-slate-400 capitalize">{t("novel title")}</p>
                                    <p className="font-semibold text-slate-800 mt-0.5!">{novelTitle}</p>
                                </div>

                                <div className="flex flex-col items-center gap-2">
                                    <p className="text-xs text-slate-400 capitalize">{t("leave review")}</p>
                                    <StarInput value={rating} onChange={setRating} />
                                </div>

                                <textarea
                                    value={text}
                                    onChange={(e) => setText(e.target.value)}
                                    placeholder={t("describe your review of the novel")}
                                    rows={4}
                                    className="w-full border border-slate-100 rounded-2xl p-4 text-sm text-slate-800 placeholder:text-slate-400 outline-none resize-none focus:border-primary-300 transition-colors bg-slate-50"
                                />

                                <button
                                    onClick={onSubmit}
                                    disabled={!rating || loading}
                                    className={`w-full py-4 rounded-2xl font-semibold text-sm transition-all
                                        ${rating && !loading
                                            ? "bg-primary-500 text-white hover:bg-primary-600 cursor-pointer"
                                            : "bg-slate-100 text-slate-300 cursor-not-allowed"}`}
                                >
                                    {loading ? "Mengirim..." : t("submit")}
                                </button>
                            </div>
                        </motion.div>
                    </div>
                </>
            )}
        </AnimatePresence>
    );
}

function TabReviews({
    novel,
    token,
    userId,
}: {
    novel: PostModel;
    token?: string;
    userId?: string;
}) {
    const { t } = useTranslation();
    const [loading, setLoading] = useState(true);
    const [fetchingMore, setFetchingMore] = useState(false);
    const [reviews, setReviews] = useState<ReviewModel[]>([]);
    const [total, setTotal] = useState(0);
    const [page, setPage] = useState(1);
    const [hasMore, setHasMore] = useState(true);
    const [showModal, setShowModal] = useState(false);
    const [editingReview, setEditingReview] = useState<ReviewModel | undefined>();
    const loaderRef = useRef<HTMLDivElement>(null);
    const LIMIT = 5;

    const avgRating = novel.total_reviews
        ? Math.round(novel.total_sum_reviews / novel.total_reviews)
        : 0;

    const fetchReviews = useCallback(async (nextPage = 1) => {
        try {
            if (nextPage === 1) setLoading(true); else setFetchingMore(true);
            const { data: res } = await getReview(token ?? "", { page: nextPage, post_id: novel.id, limit: LIMIT });
            if (res?.data) {
                const isLast = nextPage * LIMIT >= res.pagination.total;
                setReviews((prev) =>
                    nextPage === 1 ? res.data : [...prev, ...res.data.filter((r: ReviewModel) => !prev.some((p) => p.id === r.id))]
                );
                setTotal(res.pagination.total);
                setHasMore(!isLast);
                setPage(nextPage);
            }
        } catch (err: any) {
            toast.error(err?.data?.message ?? "Gagal memuat ulasan");
        } finally {
            setLoading(false);
            setFetchingMore(false);
        }
    }, [token, novel.id]);

    useEffect(() => { fetchReviews(1); }, []);

    // infinite scroll
    useEffect(() => {
        const observer = new IntersectionObserver((entries) => {
            if (entries[0].isIntersecting && hasMore && !fetchingMore) {
                fetchReviews(page + 1);
            }
        }, { threshold: 0.1 });
        if (loaderRef.current) observer.observe(loaderRef.current);
        return () => observer.disconnect();
    }, [hasMore, fetchingMore, page, fetchReviews]);

    const openCreate = () => {
        if (!token) { toast.error(t("you need to login first")); return; }
        setEditingReview(undefined);
        setShowModal(true);
    };

    return (
        <>
            <div className="bg-slate-50 rounded-2xl px-6 py-5 flex items-center justify-between mb-4!">
                <p className="font-semibold text-slate-800 text-sm capitalize">{t("total reviews")}</p>
                <div className="flex items-center gap-2">
                    <span className="text-sm text-slate-500">{total} ulasan  |</span>
                    <span className="font-bold text-slate-800">{avgRating.toFixed(1)}</span>
                    <Star className="w-4 h-4 fill-yellow-400 text-yellow-400" />
                </div>
            </div>

            <button
                onClick={openCreate}
                className="w-full bg-slate-50 hover:bg-slate-100 rounded-2xl px-6 py-5 flex items-center justify-between transition-colors cursor-pointer mb-6!"
            >
                <div className="text-left">
                    <p className="font-semibold text-slate-800 text-sm capitalize">{t("leave review")}</p>
                    <p className="text-xs text-slate-400 mt-0.5! capitalize">{t("leave your review")}</p>
                </div>
                <StarDisplay value={novel.total_ratings ?? 0} size={18} />
            </button>

            {loading ? (
                <div className="flex flex-col gap-3">
                    {Array.from({ length: 4 }).map((_, i) => (
                        <div key={i} className="flex gap-3 py-4 border-b border-slate-100 animate-pulse">
                            <div className="w-8 h-8 rounded-full bg-slate-100 shrink-0" />
                            <div className="flex-1 flex flex-col gap-2">
                                <div className="h-3 bg-slate-100 rounded-full w-1/3" />
                                <div className="h-3 bg-slate-100 rounded-full w-full" />
                                <div className="h-3 bg-slate-100 rounded-full w-2/3" />
                            </div>
                        </div>
                    ))}
                </div>
            ) : (
                <motion.div
                    initial={{ opacity: 0 }}
                    animate={{ opacity: 1 }}
                    className="flex flex-col"
                >
                    {reviews.map((review, i) => {
                        const isOwn = review.user?.id === userId;
                        return (
                            <motion.div
                                key={review.id}
                                initial={{ opacity: 0, y: 8 }}
                                animate={{ opacity: 1, y: 0 }}
                                transition={{ delay: i * 0.04 }}
                                className="flex items-start gap-3 py-4 border-b border-slate-100 group"
                            >
                                <Avatar avatar={review.user?.avatar} name={review.user?.name ?? ""} />
                                <div className="flex-1 min-w-0">
                                    <div className="flex items-center justify-between">
                                        <p className="font-semibold text-slate-800 text-sm">{review.user?.name}</p>
                                        {isOwn && (
                                            <button
                                                onClick={() => { setEditingReview(review); setShowModal(true); }}
                                                className="opacity-0 group-hover:opacity-100 p-1.5 rounded-lg hover:bg-slate-100 transition-all cursor-pointer"
                                            >
                                                <Pencil className="w-3.5 h-3.5 text-slate-500" />
                                            </button>
                                        )}
                                    </div>
                                    <p className="text-xs text-slate-500 mt-1! leading-relaxed">{review.text}</p>
                                    <div className="flex items-center justify-between mt-2!">
                                        <p className="text-xs text-slate-400">
                                            {format(new Date(review.created_at), "dd MMM yyyy")}
                                        </p>
                                        <StarDisplay value={review.value} size={12} />
                                    </div>
                                </div>
                            </motion.div>
                        );
                    })}

                    <div ref={loaderRef} className="h-4" />
                    {fetchingMore && (
                        <div className="flex justify-center py-4">
                            <div className="w-5 h-5 border-2 border-primary-500 border-t-transparent rounded-full animate-spin" />
                        </div>
                    )}
                    {reviews.length === 0 && (
                        <p className="text-sm text-slate-400 text-center py-8">Belum ada ulasan</p>
                    )}
                </motion.div>
            )}

            <ReviewModal
                open={showModal}
                novelTitle={novel.title}
                existing={editingReview}
                novelId={novel.id}
                token={token}
                onSuccess={() => fetchReviews(1)}
                onClose={() => setShowModal(false)}
            />
        </>
    );
}

function TabGoldflea({
    novel,
    token,
    userGoldflea = 0,
}: {
    novel: PostModel;
    token?: string;
    userGoldflea?: number;
}) {
    const { t } = useTranslation();
    const [loading, setLoading] = useState(true);
    const [fetchingMore, setFetchingMore] = useState(false);
    const [transactions, setTransactions] = useState<TransactionModel[]>([]);
    const [total, setTotal] = useState(0);
    const [page, setPage] = useState(1);
    const [hasMore, setHasMore] = useState(true);
    const [submitting, setSubmitting] = useState(false);
    const loaderRef = useRef<HTMLDivElement>(null);
    const LIMIT = 10;

    const fetchData = useCallback(async (nextPage = 1) => {
        try {
            if (nextPage === 1) setLoading(true); else setFetchingMore(true);
            const { data: res } = await getGoldFlea({ page: nextPage, post_id: novel.id, limit: LIMIT });
            if (res?.data) {
                const isLast = nextPage * LIMIT >= res.pagination.total;
                setTransactions((prev) =>
                    nextPage === 1 ? res.data : [...prev, ...res.data.filter((r: TransactionModel) => !prev.some((p) => p.id === r.id))]
                );
                setTotal(res.pagination.total);
                setHasMore(!isLast);
                setPage(nextPage);
            }
        } catch (err: any) {
            toast.error(err?.data?.message ?? "Gagal memuat data");
        } finally {
            setLoading(false);
            setFetchingMore(false);
        }
    }, [novel.id]);

    useEffect(() => { fetchData(1); }, []);

    useEffect(() => {
        const observer = new IntersectionObserver((entries) => {
            if (entries[0].isIntersecting && hasMore && !fetchingMore) fetchData(page + 1);
        }, { threshold: 0.1 });
        if (loaderRef.current) observer.observe(loaderRef.current);
        return () => observer.disconnect();
    }, [hasMore, fetchingMore, page, fetchData]);

    const onSupport = async () => {
        if (!token) { toast.error(t("you need to login first")); return; }
        if (userGoldflea <= 0) return;
        setSubmitting(true);
        try {
            const { data: res } = await postGoldFlea(token, { minutes: 1, post_id: novel.id });
            if (res?.data) {
                toast.success(t("success.submit"));
                fetchData(1);
            }
        } catch (err: any) {
            toast.error(err?.data?.message ?? err?.message ?? "Gagal");
        } finally {
            setSubmitting(false);
        }
    };

    return (
        <>
            <div className="bg-slate-50 rounded-2xl px-6 py-5 flex items-center justify-between mb-6!">
                <p className="font-semibold text-slate-800 text-sm capitalize">{t("total goldflea")}</p>
                <div className="flex items-center gap-2">
                    <Coins className="w-5 h-5 text-yellow-500" />
                    {loading ? (
                        <div className="w-8 h-4 bg-slate-200 rounded animate-pulse" />
                    ) : (
                        <span className="font-bold text-slate-800 text-base">{total}</span>
                    )}
                </div>
            </div>

            {loading ? (
                <div className="flex flex-col gap-3">
                    {Array.from({ length: 5 }).map((_, i) => (
                        <div key={i} className="flex gap-3 py-4 border-b border-slate-100 animate-pulse">
                            <div className="w-8 h-8 rounded-full bg-slate-100 shrink-0" />
                            <div className="flex-1 flex flex-col gap-2">
                                <div className="h-3 bg-slate-100 rounded-full w-1/3" />
                                <div className="h-3 bg-slate-100 rounded-full w-1/4" />
                            </div>
                            <div className="h-4 w-8 bg-slate-100 rounded-full" />
                        </div>
                    ))}
                </div>
            ) : (
                <motion.div
                    initial={{ opacity: 0 }}
                    animate={{ opacity: 1 }}
                    className="flex flex-col"
                >
                    {transactions.map((tx, i) => (
                        <motion.div
                            key={tx.id}
                            initial={{ opacity: 0, y: 8 }}
                            animate={{ opacity: 1, y: 0 }}
                            transition={{ delay: i * 0.03 }}
                            className="flex items-start gap-3 py-4 border-b border-slate-100"
                        >
                            <Avatar avatar={tx.user?.avatar} name={tx.user?.name ?? ""} />
                            <div className="flex-1">
                                <p className="font-semibold text-slate-800 text-sm">{tx.user?.name}</p>
                                <p className="text-xs text-slate-400 mt-0.5!">
                                    {format(new Date(tx.created_at), "dd MMM yyyy")}
                                </p>
                            </div>
                            <div className="flex items-center gap-1.5 shrink-0">
                                <Coins className="w-4 h-4 text-yellow-500" />
                                <span className="font-bold text-slate-800 text-sm">+1</span>
                            </div>
                        </motion.div>
                    ))}

                    <div ref={loaderRef} className="h-4" />
                    {fetchingMore && (
                        <div className="flex justify-center py-4">
                            <div className="w-5 h-5 border-2 border-primary-500 border-t-transparent rounded-full animate-spin" />
                        </div>
                    )}
                    {transactions.length === 0 && (
                        <p className="text-sm text-slate-400 text-center py-8">Belum ada dukungan goldflea</p>
                    )}
                </motion.div>
            )}

            <div className="sticky bottom-0 pt-4 pb-2 bg-white">
                <button
                    onClick={onSupport}
                    disabled={userGoldflea <= 0 || submitting}
                    className={`w-full flex items-center justify-center gap-2 py-4 rounded-2xl font-semibold text-sm transition-all
                        ${userGoldflea > 0 && !submitting
                            ? "bg-primary-500 text-white hover:bg-primary-600 cursor-pointer"
                            : "bg-slate-100 text-slate-400 cursor-not-allowed"}`}
                >
                    <Coins className="w-5 h-5" />
                    {submitting ? "Mengirim..." : t("support novel")}
                </button>
            </div>
        </>
    );
}

interface Props {
    novel: PostModel;
    token?: string;
    userId?: string;
    userGoldflea?: number;
}

export default function NovelDetailReviewsPage({ novel, token, userId, userGoldflea }: Props) {
    const { t, language } = useTranslation();
    const [selected, setSelected] = useState<"reviews" | "goldflea">("reviews");

    return (
        <div className="w-full max-w-2xl mx-auto! px-4 py-6 pb-20">
            <motion.a
                href={`/${language}/novel/${withSlug(novel.id, novel.slug)}`}
                initial={{ opacity: 0, x: -8 }}
                animate={{ opacity: 1, x: 0 }}
                className="inline-flex items-center gap-2 mb-5! text-sm font-medium text-slate-600 hover:text-slate-900 transition-colors cursor-pointer group"
            >
                <div className="w-8 h-8 rounded-xl border border-slate-200 flex items-center justify-center group-hover:bg-slate-50 transition-colors">
                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
                    </svg>
                </div>
                Kembali ke Novel
            </motion.a>
            <motion.div
                initial={{ opacity: 0, y: 10 }}
                animate={{ opacity: 1, y: 0 }}
                className="flex items-center bg-slate-100 rounded-full p-1 mb-6!"
            >
                {(["reviews", "goldflea"] as const).map((tab) => (
                    <button
                        key={tab}
                        onClick={() => setSelected(tab)}
                        className={`flex-1 py-2.5 rounded-full text-sm font-semibold transition-all cursor-pointer capitalize
                            ${selected === tab
                                ? "bg-primary-500 text-white shadow-sm"
                                : "text-slate-500 hover:text-slate-700"}`}
                    >
                        {t(tab)}
                    </button>
                ))}
            </motion.div>

            <AnimatePresence mode="wait">
                {selected === "reviews" ? (
                    <motion.div
                        key="reviews"
                        initial={{ opacity: 0, x: -10 }}
                        animate={{ opacity: 1, x: 0 }}
                        exit={{ opacity: 0, x: 10 }}
                        transition={{ duration: 0.2 }}
                    >
                        <TabReviews novel={novel} token={token} userId={userId} />
                    </motion.div>
                ) : (
                    <motion.div
                        key="goldflea"
                        initial={{ opacity: 0, x: 10 }}
                        animate={{ opacity: 1, x: 0 }}
                        exit={{ opacity: 0, x: -10 }}
                        transition={{ duration: 0.2 }}
                    >
                        <TabGoldflea novel={novel} token={token} userGoldflea={userGoldflea} />
                    </motion.div>
                )}
            </AnimatePresence>
        </div>
    );
}