"use client";

import { getMyAllChapters, uploadChapterImages } from "@/libs/axios/modules/chapter";
import { createPuisi, CreatePuisiBody } from "@/libs/axios/modules/puisi";
import { useTranslation } from "@/hooks/useTranslation";
import { GenreModel, TagModel } 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 { GripVertical, ImagePlus, X } from "lucide-react";
import { useRouter } from "next/navigation";
import { useCallback, useState } from "react";
import { toast } from "react-toastify";
import Breadcrumbs from "../../components/Breadcrumbs";
import { CoverUpload } from "./components/CoverUpload";
import { SearchableMultiSelect, SearchableSelect } from "./components/SearchableSelect";

const MAX_IMAGES = 2;

type AgeRange = { title: string; start: number; end: number };
type Step1Data = { title: string; targetAudience: string; targetAudienceAge: AgeRange | null; hasSubmit: boolean | null };
type Step2Data = { type: string; genre: GenreModel | null; tags: TagModel[]; blurb: string };
type FormData = Step1Data & Step2Data;

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

const TARGET_AUDIENCES = [
    { value: "male", label: "Laki-laki" },
    { value: "female", label: "Perempuan" },
];

const AGE_RANGES: AgeRange[] = [
    { title: "5+", start: 5, end: 12 },
    { title: "13+", start: 13, end: 17 },
    { title: "18+", start: 18, end: 100 },
];

const NOVEL_TYPES = [
    { value: "original", label: "Original", desc: "Karya asli buatan sendiri." },
    { value: "fan fiction", label: "Fan Fiction", desc: "Mengandung karakter/tokoh yang sudah ada." },
];

const MAX_BLURB_WORDS = 100;

function wordCount(text: string) {
    return text.trim() === "" ? 0 : text.trim().split(/\s+/).length;
}

function FieldWrapper({ label, children }: { label: string; children: React.ReactNode }) {
    return (
        <div className="flex flex-col gap-1.5">
            <label className="text-sm font-semibold text-slate-700">{label}</label>
            {children}
        </div>
    );
}

const inputCls = "w-full px-4 py-3 rounded-xl border border-slate-200 text-sm text-slate-800 bg-white focus:outline-none focus:ring-2 focus:ring-primary-300 focus:border-primary-300 transition cursor-pointer appearance-none";

function StepIndicator({ current }: { current: number }) {
    return (
        <div className="flex items-center justify-center gap-3 py-4 border-b border-slate-100">
            {[1, 2, 3].map((step) => (
                <div key={step} className="flex items-center gap-3">
                    <div className={`w-7 h-7 rounded-full flex items-center justify-center text-xs font-bold transition-all duration-300
                        ${step === current ? "bg-primary-500 text-white shadow-md shadow-primary-500/30 scale-110"
                            : step < current ? "bg-primary-100 text-primary-500"
                                : "bg-slate-100 text-slate-400"}`}>
                        {step < current
                            ? <svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" /></svg>
                            : step}
                    </div>
                    {step < 3 && <div className={`w-10 h-0.5 rounded-full transition-all duration-300 ${step < current ? "bg-primary-300" : "bg-slate-100"}`} />}
                </div>
            ))}
        </div>
    );
}

function Step1({
    data,
    onChange,
    coverPreview,
    onCoverChange,
}: {
    data: Step1Data;
    onChange: (p: Partial<Step1Data>) => void;
    coverPreview: string;
    onCoverChange: (file: File, previewUrl: string) => void;
}) {
    return (
        <div className="flex flex-col">
            <CoverUpload image={coverPreview} onChange={onCoverChange} />

            <div className="flex flex-col gap-5 p-5">
                <FieldWrapper label="Judul Puisi">
                    <input
                        type="text"
                        value={data.title}
                        onChange={(e) => onChange({ title: e.target.value })}
                        placeholder="Masukkan judul puisi"
                        className={inputCls}
                    />
                </FieldWrapper>

                <FieldWrapper label="Target Pembaca">
                    <div className="relative">
                        <select
                            value={data.targetAudience}
                            onChange={(e) => onChange({ targetAudience: e.target.value })}
                            className={inputCls}
                        >
                            <option value="" disabled>Pilih target pembaca</option>
                            {TARGET_AUDIENCES.map(a => (
                                <option key={a.value} value={a.value}>{a.label}</option>
                            ))}
                        </select>
                        <svg className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
                        </svg>
                    </div>
                </FieldWrapper>

                <FieldWrapper label="Usia Target Pembaca">
                    <div className="relative">
                        <select
                            value={data.targetAudienceAge?.title ?? ""}
                            onChange={(e) => {
                                const found = AGE_RANGES.find(a => a.title === e.target.value);
                                if (found) onChange({ targetAudienceAge: found });
                            }}
                            className={inputCls}
                        >
                            <option value="" disabled>Pilih usia target</option>
                            {AGE_RANGES.map(a => (
                                <option key={a.title} value={a.title}>{a.title}</option>
                            ))}
                        </select>
                        <svg className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
                        </svg>
                    </div>
                </FieldWrapper>

                <FieldWrapper label="Apakah karya anda tersedia di platform lain?">
                    <div className="flex gap-3">
                        {[{ value: true, label: "Ya" }, { value: false, label: "Tidak" }].map((opt) => (
                            <button
                                key={String(opt.value)}
                                type="button"
                                onClick={() => onChange({ hasSubmit: opt.value })}
                                className={`flex-1 py-3 rounded-xl border-2 text-sm font-semibold transition-all cursor-pointer
                                    ${data.hasSubmit === opt.value
                                        ? "border-primary-500 bg-primary-50 text-primary-600"
                                        : "border-slate-200 text-slate-500 hover:border-slate-300"
                                    }`}
                            >
                                {opt.label}
                            </button>
                        ))}
                    </div>
                </FieldWrapper>
            </div>
        </div>
    );
}

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={`Gambar puisi ${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>
            <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>
    );
}

function ImagesPicker({
    images,
    onPick,
    onRemove,
    onReorder,
}: {
    images: LocalImage[];
    onPick: (files: FileList | null) => void;
    onRemove: (id: string) => void;
    onReorder: (images: LocalImage[]) => void;
}) {
    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;
        const oldIndex = images.findIndex((img) => img.id === active.id);
        const newIndex = images.findIndex((img) => img.id === over.id);
        onReorder(arrayMove(images, oldIndex, newIndex));
    };

    return (
        <FieldWrapper label={`Gambar Puisi (${images.length}/${MAX_IMAGES})`}>
            {images.length > 0 && (
                <p className="text-xs text-slate-400 flex items-center gap-1.5 mb-1">
                    <GripVertical className="w-3.5 h-3.5" />
                    Seret gambar buat ngatur urutan.
                </p>
            )}

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

            {images.length < MAX_IMAGES && (
                <label className="flex flex-col items-center justify-center gap-2 py-8 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>
                    <input
                        type="file"
                        accept="image/*"
                        multiple
                        className="hidden"
                        onChange={(e) => {
                            onPick(e.target.files);
                            e.target.value = "";
                        }}
                    />
                </label>
            )}
            <p className="text-xs text-slate-400">Gambar inilah yang akan dibaca sebagai isi puisimu, maksimal {MAX_IMAGES} gambar.</p>
        </FieldWrapper>
    );
}

function Step2({
    data, onChange, genres, tags, images, onPickImages, onRemoveImage, onReorderImages,
}: {
    data: Step2Data;
    onChange: (p: Partial<Step2Data>) => void;
    genres: GenreModel[];
    tags: TagModel[];
    images: LocalImage[];
    onPickImages: (files: FileList | null) => void;
    onRemoveImage: (id: string) => void;
    onReorderImages: (images: LocalImage[]) => void;
}) {
    const words = wordCount(data.blurb);

    return (
        <div className="flex flex-col gap-5 p-5">
            <FieldWrapper label="Tipe Puisi">
                <div className="flex flex-col gap-2">
                    {NOVEL_TYPES.map((opt) => (
                        <button
                            key={opt.value}
                            type="button"
                            onClick={() => onChange({ type: opt.value })}
                            className={`w-full text-left px-4 py-3.5 rounded-xl border-2 transition-all cursor-pointer
                                ${data.type === opt.value
                                    ? "border-primary-500 bg-primary-50/40"
                                    : "border-slate-200 hover:border-slate-300"
                                }`}
                        >
                            <p className={`text-sm font-semibold ${data.type === opt.value ? "text-primary-600" : "text-slate-700"}`}>
                                {opt.label}
                            </p>
                            <p className={`text-xs mt-0.5 ${data.type === opt.value ? "text-primary-400" : "text-slate-400"}`}>
                                {opt.desc}
                            </p>
                        </button>
                    ))}
                </div>
            </FieldWrapper>

            <FieldWrapper label="Genre">
                <SearchableSelect
                    value={data.genre}
                    options={genres}
                    onSelect={(genre) => onChange({ genre })}
                    placeholder="Pilih genre"
                />
            </FieldWrapper>

            <FieldWrapper label={`Tag (${data.tags.length}/7)`}>
                <div className="flex flex-wrap items-center gap-2 p-3 rounded-xl border border-slate-200 bg-white min-h-12">
                    {data.tags.map(tag => (
                        <span key={tag.id} className="inline-flex items-center gap-1 px-3 py-1 rounded-full bg-primary-100 text-primary-700 text-xs font-semibold">
                            {tag.title}
                            <button
                                type="button"
                                onClick={() => onChange({ tags: data.tags.filter(t => t.id !== tag.id) })}
                                className="hover:text-primary-900 transition-colors cursor-pointer"
                            >
                                <X className="w-3 h-3" />
                            </button>
                        </span>
                    ))}
                    <SearchableMultiSelect
                        options={tags}
                        excludeIds={data.tags.map(t => t.id)}
                        onAdd={(tag) => onChange({ tags: [...data.tags, tag] })}
                        placeholder={data.tags.length === 0 ? "Pilih tag..." : "+ Tambah tag"}
                        disabled={data.tags.length >= 7}
                    />
                </div>
                <p className="text-xs text-slate-400">Pilih maksimal 7 tag yang relevan dengan puisimu.</p>
            </FieldWrapper>

            <FieldWrapper label="Blurb Puisi">
                <textarea
                    value={data.blurb}
                    onChange={(e) => onChange({ blurb: e.target.value })}
                    placeholder="Tulis blurb puisi..."
                    rows={5}
                    className="w-full px-4 py-3 rounded-xl border border-slate-200 text-sm text-slate-800 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-primary-300 focus:border-primary-300 resize-none transition"
                />
                <p className={`text-xs ${words > MAX_BLURB_WORDS ? "text-red-500" : "text-slate-400"}`}>
                    {words} / {MAX_BLURB_WORDS} kata
                </p>
            </FieldWrapper>

            <ImagesPicker
                images={images}
                onPick={onPickImages}
                onRemove={onRemoveImage}
                onReorder={onReorderImages}
            />
        </div>
    );
}

function ReviewRow({ label, value }: { label: string; value: React.ReactNode }) {
    return (
        <div className="flex flex-col gap-0.5">
            <span className="text-xs text-slate-400">{label}</span>
            <span className="text-sm font-semibold text-slate-800">{value || "-"}</span>
        </div>
    );
}

function Step3({
    data,
    images,
    coverPreview,
    onCoverChange,
}: {
    data: FormData;
    images: LocalImage[];
    coverPreview: string;
    onCoverChange: (file: File, previewUrl: string) => void;
}) {
    return (
        <div className="flex flex-col">
            <CoverUpload image={coverPreview} onChange={onCoverChange} />
            <div className="h-1.5 bg-slate-100" />
            <div className="flex flex-col gap-5 p-5">
                <ReviewRow label="Judul Puisi" value={data.title} />
                <div className="grid grid-cols-2 gap-4">
                    <ReviewRow label="Tipe Puisi" value={NOVEL_TYPES.find(t => t.value === data.type)?.label} />
                    <ReviewRow label="Genre" value={data.genre?.title} />
                </div>
                <div className="grid grid-cols-2 gap-4">
                    <ReviewRow label="Target Pembaca" value={TARGET_AUDIENCES.find(a => a.value === data.targetAudience)?.label} />
                    <ReviewRow label="Usia Target" value={data.targetAudienceAge?.title} />
                </div>
                <ReviewRow
                    label="Tag"
                    value={
                        <div className="flex flex-wrap gap-1.5 mt-1">
                            {data.tags.map(tag => (
                                <span key={tag.id} className="px-2.5 py-1 rounded-full bg-slate-100 text-xs text-slate-600 font-normal">
                                    {tag.title}
                                </span>
                            ))}
                        </div>
                    }
                />
                <ReviewRow label="Platform lain" value={data.hasSubmit ? "Ya" : "Tidak"} />
                <div>
                    <span className="text-xs text-slate-400">Blurb</span>
                    <p className="text-sm text-slate-700 leading-relaxed mt-1">{data.blurb}</p>
                </div>
                <div>
                    <span className="text-xs text-slate-400">Gambar Puisi ({images.length}/{MAX_IMAGES})</span>
                    <div className="grid grid-cols-2 gap-3 mt-2">
                        {images.map((img, index) => (
                            <div key={img.id} className="relative aspect-3/4 rounded-xl overflow-hidden bg-slate-100 border border-slate-200">
                                <img src={img.preview} alt={`Gambar puisi ${index + 1}`} className="w-full h-full object-cover" />
                            </div>
                        ))}
                    </div>
                </div>
            </div>
        </div>
    );
}

interface Props {
    token: string;
    genres: GenreModel[];
    tags: TagModel[];
}

export default function CreatePuisiPage({ token, genres, tags }: Props) {
    const router = useRouter();
    const { language } = useTranslation();
    const [step, setStep] = useState(1);
    const [submitting, setSubmitting] = useState(false);

    const [coverFile, setCoverFile] = useState<File | null>(null);
    const [coverPreview, setCoverPreview] = useState<string>("");
    const [images, setImages] = useState<LocalImage[]>([]);

    const handleCoverChange = useCallback((file: File, previewUrl: string) => {
        setCoverFile(file);
        setCoverPreview(previewUrl);
    }, []);

    const [form, setForm] = useState<FormData>({
        title: "", targetAudience: "", targetAudienceAge: null, hasSubmit: null,
        type: "", genre: null, tags: [], blurb: "",
    });

    const patch = useCallback((data: Partial<FormData>) => {
        setForm((prev) => ({ ...prev, ...data }));
    }, []);

    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 puisi`, { toastId: "max-images" });
            return;
        }

        const accepted = incoming.slice(0, remainingSlots);
        if (incoming.length > accepted.length) {
            toast.error(`Maksimal ${MAX_IMAGES} gambar puisi`, { 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 onRemoveImage = (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 step1Valid = !!(coverFile && form.title && form.targetAudience && form.targetAudienceAge && form.hasSubmit !== null);
    const step2Valid = !!(form.type && form.genre && form.tags.length > 0 && form.blurb && wordCount(form.blurb) <= MAX_BLURB_WORDS && images.length > 0);
    const canNext = step === 1 ? step1Valid : step === 2 ? step2Valid : true;

    const onNext = async () => {
        if (step < 3) { setStep((s) => s + 1); return; }
        if (!form.targetAudienceAge || form.hasSubmit === null || !form.genre || !coverFile) return;

        setSubmitting(true);
        try {
            const body: CreatePuisiBody = {
                title: form.title,
                type: form.type,
                description: form.blurb,
                genre_id: form.genre.id,
                source: form.type,
                sex: form.targetAudience,
                has_submit: form.hasSubmit,
                age: {
                    title: form.targetAudienceAge.title,
                    start: form.targetAudienceAge.start,
                    end: form.targetAudienceAge.end,
                },
                tags: form.tags.map((t) => t.id),
                attachment: coverFile,
            };

            const { data: res } = await createPuisi(token, body);
            const postId = res?.data?.id;

            if (postId && images.length > 0) {
                const { data: chapterRes } = await getMyAllChapters(token, { post_id: postId });
                const chapterId = chapterRes?.data?.data?.[0]?.id;
                if (chapterId) {
                    await uploadChapterImages(token, chapterId, images.map((img) => img.file));
                }
            }

            if (postId) router.push(`/${language}/user/puisi`);
        } catch (err: any) {
            console.error(err?.data?.message ?? err.message);
            toast.error(err?.data?.message ?? err.message ?? "Gagal menyimpan puisi");
        } finally {
            setSubmitting(false);
        }
    };

    return (
        <div className="flex flex-col gap-6 w-full">
            <Breadcrumbs
                title="Dashboard"
                subtitle={[
                    { title: "Daftar Puisi", href: "/user/puisi" },
                    { title: "Buat Puisi Baru", href: "/user/puisi/create" },
                ]}
                href="/user"
            />

            <div className="flex items-center gap-3 bg-white p-4 rounded-xl border border-slate-100 shadow-sm">
                <button
                    onClick={() => step > 1 ? setStep(s => s - 1) : 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>
                <div>
                    <h1 className="text-base font-semibold text-slate-900">Buat Puisi Baru</h1>
                    <p className="text-xs text-slate-400">Langkah {step} dari 3</p>
                </div>
            </div>

            <div className="w-full bg-white rounded-2xl shadow-sm border border-slate-100 overflow-hidden">
                <StepIndicator current={step} />

                <div>
                    {step === 1 && (
                        <Step1
                            data={form}
                            onChange={patch}
                            coverPreview={coverPreview}
                            onCoverChange={handleCoverChange}
                        />
                    )}
                    {step === 2 && (
                        <Step2
                            data={form}
                            onChange={patch}
                            genres={genres}
                            tags={tags}
                            images={images}
                            onPickImages={onPickImages}
                            onRemoveImage={onRemoveImage}
                            onReorderImages={setImages}
                        />
                    )}
                    {step === 3 && (
                        <Step3
                            data={form}
                            images={images}
                            coverPreview={coverPreview}
                            onCoverChange={handleCoverChange}
                        />
                    )}
                </div>

                <div className="px-5 py-4 bg-white border-t border-slate-100">
                    <button
                        onClick={onNext}
                        disabled={!canNext || submitting}
                        className={`w-full py-3 rounded-xl text-sm font-semibold transition-all duration-200 cursor-pointer
                            ${canNext && !submitting
                                ? "bg-primary-500 text-white hover:bg-primary-600 shadow-md shadow-primary-500/20 hover:-translate-y-0.5 active:translate-y-0"
                                : "bg-slate-100 text-slate-400 cursor-not-allowed"
                            }`}
                    >
                        {submitting ? "Menyimpan..." : step === 3 ? "Buat Puisi" : "Selanjutnya"}
                    </button>
                </div>
            </div>
        </div>
    );
}
