"use client";

import Breadcrumbs from "@/components/user/components/Breadcrumbs";
import { createChapter, uploadChapterImages } from "@/libs/axios/modules/chapter";
import { getMyKomikDetail } from "@/libs/axios/modules/komik";
import { PostModel } from "@/models";
import {
    closestCenter,
    DndContext,
    DragEndEvent,
    KeyboardSensor,
    PointerSensor,
    useSensor,
    useSensors,
} from "@dnd-kit/core";
import {
    arrayMove,
    rectSortingStrategy,
    SortableContext,
    sortableKeyboardCoordinates,
    useSortable,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { format } from "date-fns";
import { Calendar, GripVertical, ImagePlus, X } from "lucide-react";
import { useRouter } from "next/navigation";
import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "react-toastify";

const MAX_IMAGES = 10;
const MIN_COINS = 4;
const MAX_COINS = 20;

type LocalImage = {
    id: string;
    file: File;
    preview: string;
};

interface Props {
    token: string;
    postId: string;
}

function SortableImageThumb({
    id,
    preview,
    index,
    onRemove,
}: {
    id: string;
    preview: string;
    index: number;
    onRemove: () => void;
}) {
    const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id });

    const style: React.CSSProperties = {
        transform: CSS.Transform.toString(transform),
        transition,
        opacity: isDragging ? 0.6 : 1,
        zIndex: isDragging ? 10 : undefined,
    };

    return (
        <div
            ref={setNodeRef}
            style={style}
            {...attributes}
            {...listeners}
            className="relative group rounded-xl overflow-hidden border border-slate-200 bg-slate-50 cursor-grab active:cursor-grabbing shadow-sm touch-none"
        >
            <img
                src={preview}
                alt={`Halaman ${index + 1}`}
                className="w-full aspect-3/4 object-cover pointer-events-none select-none"
            />
            <span className="absolute top-2 left-2 w-6 h-6 rounded-full bg-black/60 text-white text-xs font-semibold flex items-center justify-center">
                {index + 1}
            </span>
            <div className="absolute top-2 right-2 w-6 h-6 rounded-full bg-black/40 text-white/80 flex items-center justify-center pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity">
                <GripVertical className="w-3.5 h-3.5" />
            </div>
            <button
                type="button"
                onClick={(e) => {
                    e.stopPropagation();
                    onRemove();
                }}
                onPointerDown={(e) => e.stopPropagation()}
                className="absolute bottom-2 right-2 w-6 h-6 rounded-full bg-black/60 text-white flex items-center justify-center hover:bg-red-500 transition-colors cursor-pointer z-10"
            >
                <X className="w-3.5 h-3.5" />
            </button>
        </div>
    );
}

export default function CreateEpisodePage({ token, postId }: Props) {
    const router = useRouter();
    const [komik, setKomik] = useState<PostModel | null>(null);
    const [title, setTitle] = useState("");
    const [coins, setCoins] = useState<number | "">(MIN_COINS);
    const [publishedAt, setPublishedAt] = useState<Date>(new Date());
    const [images, setImages] = useState<LocalImage[]>([]);
    const [saving, setSaving] = useState(false);
    const dateRef = useRef<HTMLInputElement>(null);
    const fileInputRef = useRef<HTMLInputElement>(null);
    const imagesRef = useRef<LocalImage[]>([]);
    imagesRef.current = images;

    useEffect(() => {
        const load = async () => {
            try {
                const { data: res } = await getMyKomikDetail(token, postId);
                if (res?.data) setKomik(res.data);
            } catch (err) {
                console.error(err);
            }
        };
        load();
    }, [postId, token]);

    useEffect(() => {
        return () => {
            imagesRef.current.forEach((img) => URL.revokeObjectURL(img.preview));
        };
    }, []);

    const coinsValid = typeof coins === "number" && coins >= MIN_COINS && coins <= MAX_COINS;
    const canSave = !!(title && publishedAt && coinsValid && images.length > 0);

    const onPickImages = (files: FileList | null) => {
        if (!files || files.length === 0) return;

        const incoming = Array.from(files);
        const remainingSlots = MAX_IMAGES - images.length;

        if (remainingSlots <= 0) {
            toast.error(`Maksimal ${MAX_IMAGES} gambar per episode`, { toastId: "max-images" });
            return;
        }

        const accepted = incoming.slice(0, remainingSlots);
        if (incoming.length > accepted.length) {
            toast.error(`Maksimal ${MAX_IMAGES} gambar per episode`, { toastId: "max-images" });
        }

        const newImages: LocalImage[] = accepted.map((file) => ({
            id: `${file.name}-${file.lastModified}-${Math.random().toString(36).slice(2)}`,
            file,
            preview: URL.createObjectURL(file),
        }));

        setImages((prev) => [...prev, ...newImages]);
    };

    const removeImage = (id: string) => {
        setImages((prev) => {
            const target = prev.find((img) => img.id === id);
            if (target) URL.revokeObjectURL(target.preview);
            return prev.filter((img) => img.id !== id);
        });
    };

    const sensors = useSensors(
        useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
        useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
    );

    const handleDragEnd = (event: DragEndEvent) => {
        const { active, over } = event;
        if (!over || active.id === over.id) return;

        setImages((prev) => {
            const oldIndex = prev.findIndex((img) => img.id === active.id);
            const newIndex = prev.findIndex((img) => img.id === over.id);
            return arrayMove(prev, oldIndex, newIndex);
        });
    };

    const onSave = useCallback(async () => {
        if (!canSave || saving) return;
        setSaving(true);
        try {
            const { data: res } = await createChapter(token, {
                title,
                post_id: postId,
                coins: coins as number,
                published_at: publishedAt,
            });
            const chapterId = res?.data?.id;
            if (chapterId) {
                await uploadChapterImages(token, chapterId, images.map((img) => img.file));
            }
            router.back();
        } catch (err: any) {
            console.error(err?.data?.message ?? err.message);
            toast.error("Gagal menyimpan episode");
        } finally {
            setSaving(false);
        }
    }, [canSave, saving, title, postId, coins, publishedAt, images, token, router]);

    const toInputValue = (d: Date) => format(d, "yyyy-MM-dd'T'HH:mm");

    return (
        <div className="flex flex-col gap-6 w-full">
            <Breadcrumbs
                title="Dashboard"
                subtitle={[
                    { title: "Daftar Komik", href: "/user/komik" },
                    { title: komik?.title || "", href: "/user/komik" },
                    { title: "Tambah Episode Baru", href: `/user/komik/chapter/${komik?.id}/create` },
                ]}
                href="/user"
            />

            <div className="sticky top-0 z-10 bg-white border-b border-slate-100 rounded-t-xl shadow-sm">
                <div className="flex items-center justify-between px-4 py-3">
                    <div className="flex items-center gap-2">
                        <button
                            onClick={() => router.back()}
                            className="w-9 h-9 rounded-xl border border-slate-200 flex items-center justify-center hover:bg-slate-50 transition-colors cursor-pointer"
                        >
                            <svg className="w-4 h-4 text-slate-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
                            </svg>
                        </button>
                        <span className="text-base font-semibold text-slate-800">Tambah Episode</span>
                    </div>
                    <button
                        onClick={onSave}
                        disabled={!canSave || saving}
                        className={`px-4 py-1.5 rounded-full text-sm font-semibold border transition-all cursor-pointer
                        ${canSave && !saving
                                ? "border-primary-500 text-primary-500 hover:bg-primary-50"
                                : "border-slate-200 text-slate-300 cursor-not-allowed"}`}
                    >
                        {saving ? "Menyimpan..." : "Simpan"}
                    </button>
                </div>

                <div className="flex items-center gap-2 px-4 bg-slate-50 border-t border-slate-100">
                    <input
                        type="text"
                        value={title}
                        onChange={(e) => setTitle(e.target.value)}
                        placeholder="Tulis judul episode..."
                        className="flex-1 py-3 bg-transparent text-sm text-slate-800 placeholder:text-slate-400 outline-none font-medium"
                    />
                </div>

                <div
                    className="flex items-center gap-2 px-4 py-2.5 bg-slate-50 border-t border-slate-100 cursor-pointer hover:bg-slate-100 transition-colors"
                    onClick={() => dateRef.current?.showPicker()}
                >
                    <Calendar className="w-4 h-4 text-slate-400 shrink-0" />
                    <span className="text-xs text-slate-400">
                        Tanggal Terbit:{" "}
                        <span className="font-semibold text-slate-700">
                            {format(publishedAt, "dd MMM yyyy, HH:mm")}
                        </span>
                    </span>
                    <input
                        ref={dateRef}
                        type="datetime-local"
                        value={toInputValue(publishedAt)}
                        min={toInputValue(new Date())}
                        onChange={(e) => e.target.value && setPublishedAt(new Date(e.target.value))}
                        className="sr-only"
                        readOnly
                    />
                </div>

                <div className="flex items-center gap-2 px-4 py-2.5 bg-slate-50 border-t border-slate-100">
                    <span className="text-xs text-slate-400 shrink-0">Harga Episode:</span>
                    <input
                        type="number"
                        min={MIN_COINS}
                        max={MAX_COINS}
                        value={coins}
                        onChange={(e) => {
                            const v = e.target.value;
                            setCoins(v === "" ? "" : Number(v));
                        }}
                        className="w-20 px-2 py-1 text-sm font-semibold text-slate-800 bg-white border border-slate-200 rounded-lg outline-none focus:ring-2 focus:ring-primary-300"
                    />
                    <span className="text-xs text-slate-400">koin ({MIN_COINS}–{MAX_COINS})</span>
                    {coins !== "" && !coinsValid && (
                        <span className="text-xs text-red-500">Harus {MIN_COINS}-{MAX_COINS} koin</span>
                    )}
                </div>
            </div>

            <div className="bg-white rounded-xl shadow-sm p-5 flex flex-col gap-4">
                <div className="flex items-center justify-between">
                    <h2 className="text-sm font-semibold text-slate-800">Halaman Episode</h2>
                    <span className="text-xs text-slate-400">{images.length}/{MAX_IMAGES} gambar</span>
                </div>

                {images.length > 0 && (
                    <p className="text-xs text-slate-400 flex items-center gap-1.5">
                        <GripVertical className="w-3.5 h-3.5" />
                        Seret gambar buat ngatur urutan halaman.
                    </p>
                )}

                <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
                    <SortableContext items={images.map((img) => img.id)} strategy={rectSortingStrategy}>
                        <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
                            {images.map((img, index) => (
                                <SortableImageThumb
                                    key={img.id}
                                    id={img.id}
                                    preview={img.preview}
                                    index={index}
                                    onRemove={() => removeImage(img.id)}
                                />
                            ))}
                        </div>
                    </SortableContext>
                </DndContext>

                {images.length < MAX_IMAGES && (
                    <button
                        type="button"
                        onClick={() => fileInputRef.current?.click()}
                        className="flex flex-col items-center justify-center gap-2 py-10 rounded-xl border-2 border-dashed border-slate-200 text-slate-400 hover:border-primary-300 hover:text-primary-500 transition-colors cursor-pointer"
                    >
                        <ImagePlus className="w-6 h-6" />
                        <span className="text-sm font-medium">Tambah Gambar</span>
                    </button>
                )}

                <input
                    ref={fileInputRef}
                    type="file"
                    accept="image/*"
                    multiple
                    className="hidden"
                    onChange={(e) => {
                        onPickImages(e.target.files);
                        e.target.value = "";
                    }}
                />
            </div>
        </div>
    );
}
