"use client";

import { useMemo, useState } from "react";
import {
    ImageIcon,
    Loader2Icon,
    PencilIcon,
    PlusIcon,
    RefreshCwIcon,
    SaveIcon,
    Trash2Icon,
} from "lucide-react";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from "@/components/ui/table";
import type {
    CollectionPhoto,
    PhotoCollection,
} from "@/types/admin/collection";

type CollectionForm = {
    id: string | null;
    title: string;
    slug: string;
    description: string;
    coverPhotoId: string | null;
    isPublished: boolean;
    photoIds: string[];
};

type ApiResponse<T> = {
    ok: boolean;
    data: T;
    error?: string;
};

const emptyForm: CollectionForm = {
    id: null,
    title: "",
    slug: "",
    description: "",
    coverPhotoId: null,
    isPublished: false,
    photoIds: [],
};

function getPhotoUrl(photo: CollectionPhoto) {
    const urls = photo.urls as Record<string, string> | undefined;
    return photo.oss_url ?? urls?.small ?? urls?.thumb ?? urls?.regular ?? "";
}

function getPhotoLabel(photo: CollectionPhoto) {
    return (
        photo.alt_description ||
        photo.description ||
        photo.unsplash_id ||
        "Picked photo"
    );
}

function getFormFromCollection(collection: PhotoCollection): CollectionForm {
    return {
        id: collection.id,
        title: collection.title,
        slug: collection.slug,
        description: collection.description ?? "",
        coverPhotoId: collection.cover_photo_id,
        isPublished: collection.is_published,
        photoIds: collection.photos.map((photo) => photo.id),
    };
}

export function CollectionsManager({
    initialCollections,
    initialPickedPhotos,
}: {
    initialCollections: PhotoCollection[];
    initialPickedPhotos: CollectionPhoto[];
}) {
    const [collections, setCollections] =
        useState<PhotoCollection[]>(initialCollections);
    const [pickedPhotos, setPickedPhotos] =
        useState<CollectionPhoto[]>(initialPickedPhotos);
    const [form, setForm] = useState<CollectionForm>(emptyForm);
    const [saving, setSaving] = useState(false);
    const [refreshing, setRefreshing] = useState(false);
    const [deletingId, setDeletingId] = useState<string | null>(null);
    const [error, setError] = useState<string | null>(null);

    const selectedPhotoIds = useMemo(
        () => new Set(form.photoIds),
        [form.photoIds],
    );

    const selectedPhotos = useMemo(
        () =>
            form.photoIds
                .map((photoId) =>
                    pickedPhotos.find((photo) => photo.id === photoId),
                )
                .filter((photo): photo is CollectionPhoto => Boolean(photo)),
        [form.photoIds, pickedPhotos],
    );

    const updateForm = (patch: Partial<CollectionForm>) => {
        setForm((current) => ({ ...current, ...patch }));
    };

    const startNew = () => {
        setError(null);
        setForm(emptyForm);
    };

    const togglePhoto = (photoId: string) => {
        setForm((current) => {
            const exists = current.photoIds.includes(photoId);
            const photoIds = exists
                ? current.photoIds.filter((id) => id !== photoId)
                : [...current.photoIds, photoId];
            const coverPhotoId =
                current.coverPhotoId && photoIds.includes(current.coverPhotoId)
                    ? current.coverPhotoId
                    : (photoIds[0] ?? null);

            return {
                ...current,
                photoIds,
                coverPhotoId,
            };
        });
    };

    const saveCollection = async () => {
        setSaving(true);
        setError(null);

        try {
            const res = await fetch(
                form.id
                    ? `/api/admin/photo-collections/${form.id}`
                    : "/api/admin/photo-collections",
                {
                    method: form.id ? "PATCH" : "POST",
                    headers: {
                        "content-type": "application/json",
                    },
                    body: JSON.stringify({
                        title: form.title,
                        slug: form.slug || null,
                        description: form.description || null,
                        coverPhotoId: form.coverPhotoId,
                        isPublished: form.isPublished,
                        photoIds: form.photoIds,
                    }),
                },
            );
            const json = (await res.json()) as ApiResponse<PhotoCollection>;

            if (!json.ok) {
                throw new Error(json.error || "Failed to save collection.");
            }

            setCollections((current) => {
                const exists = current.some(
                    (collection) => collection.id === json.data.id,
                );

                if (exists) {
                    return current.map((collection) =>
                        collection.id === json.data.id ? json.data : collection,
                    );
                }

                return [json.data, ...current];
            });
            setForm(getFormFromCollection(json.data));
        } catch (err) {
            setError(err instanceof Error ? err.message : "Unknown error.");
        } finally {
            setSaving(false);
        }
    };

    const deleteCollection = async (collection: PhotoCollection) => {
        if (!confirm(`Delete "${collection.title}"?`)) {
            return;
        }

        setDeletingId(collection.id);
        setError(null);

        try {
            const res = await fetch(
                `/api/admin/photo-collections/${collection.id}`,
                {
                    method: "DELETE",
                },
            );
            const json = (await res.json()) as ApiResponse<unknown>;

            if (!json.ok) {
                throw new Error(json.error || "Failed to delete collection.");
            }

            setCollections((current) =>
                current.filter((item) => item.id !== collection.id),
            );

            if (form.id === collection.id) {
                setForm(emptyForm);
            }
        } catch (err) {
            setError(err instanceof Error ? err.message : "Unknown error.");
        } finally {
            setDeletingId(null);
        }
    };

    const refreshPickedPhotos = async () => {
        setRefreshing(true);
        setError(null);

        try {
            const res = await fetch(
                "/api/admin/gallery-photos?picked=true&per_page=100",
            );
            const json = (await res.json()) as ApiResponse<CollectionPhoto[]>;

            if (!json.ok) {
                throw new Error(json.error || "Failed to refresh photos.");
            }

            setPickedPhotos(json.data);
        } catch (err) {
            setError(err instanceof Error ? err.message : "Unknown error.");
        } finally {
            setRefreshing(false);
        }
    };

    return (
        <main className="grid flex-1 gap-4 p-4 lg:grid-cols-[minmax(0,1fr)_420px] lg:p-6">
            <section className="flex min-w-0 flex-col gap-4">
                <div className="flex items-center justify-between gap-3">
                    <h2 className="text-lg font-semibold">Collections</h2>
                    <Button onClick={startNew}>
                        <PlusIcon />
                        New
                    </Button>
                </div>

                <div className="overflow-hidden rounded-lg border">
                    <Table>
                        <TableHeader>
                            <TableRow>
                                <TableHead>Title</TableHead>
                                <TableHead>Photos</TableHead>
                                <TableHead>Status</TableHead>
                                <TableHead className="w-28">Actions</TableHead>
                            </TableRow>
                        </TableHeader>
                        <TableBody>
                            {collections.map((collection) => (
                                <TableRow key={collection.id}>
                                    <TableCell>
                                        <div className="flex items-center gap-3">
                                            <div className="bg-muted relative size-12 shrink-0 overflow-hidden rounded-md">
                                                {collection.cover_photo ? (
                                                    // eslint-disable-next-line @next/next/no-img-element
                                                    <img
                                                        src={getPhotoUrl(
                                                            collection.cover_photo,
                                                        )}
                                                        alt={collection.title}
                                                        className="size-full object-cover"
                                                    />
                                                ) : (
                                                    <ImageIcon className="text-muted-foreground absolute top-1/2 left-1/2 size-4 -translate-x-1/2 -translate-y-1/2" />
                                                )}
                                            </div>
                                            <div className="min-w-0">
                                                <div className="truncate font-medium">
                                                    {collection.title}
                                                </div>
                                                <div className="text-muted-foreground truncate font-mono text-xs">
                                                    {collection.slug}
                                                </div>
                                            </div>
                                        </div>
                                    </TableCell>
                                    <TableCell>
                                        {collection.photos.length}
                                    </TableCell>
                                    <TableCell>
                                        <Badge
                                            variant={
                                                collection.is_published
                                                    ? "default"
                                                    : "secondary"
                                            }
                                        >
                                            {collection.is_published
                                                ? "Published"
                                                : "Draft"}
                                        </Badge>
                                    </TableCell>
                                    <TableCell>
                                        <div className="flex gap-1">
                                            <Button
                                                size="icon-sm"
                                                variant="ghost"
                                                onClick={() =>
                                                    setForm(
                                                        getFormFromCollection(
                                                            collection,
                                                        ),
                                                    )
                                                }
                                            >
                                                <PencilIcon />
                                            </Button>
                                            <Button
                                                size="icon-sm"
                                                variant="ghost"
                                                disabled={
                                                    deletingId === collection.id
                                                }
                                                onClick={() =>
                                                    void deleteCollection(
                                                        collection,
                                                    )
                                                }
                                            >
                                                {deletingId ===
                                                collection.id ? (
                                                    <Loader2Icon className="animate-spin" />
                                                ) : (
                                                    <Trash2Icon />
                                                )}
                                            </Button>
                                        </div>
                                    </TableCell>
                                </TableRow>
                            ))}
                            {collections.length === 0 && (
                                <TableRow>
                                    <TableCell
                                        colSpan={4}
                                        className="text-muted-foreground h-32 text-center text-sm"
                                    >
                                        No collections yet.
                                    </TableCell>
                                </TableRow>
                            )}
                        </TableBody>
                    </Table>
                </div>
            </section>

            <aside className="flex min-w-0 flex-col gap-4">
                <Card>
                    <CardHeader>
                        <CardTitle>
                            {form.id ? "Edit collection" : "New collection"}
                        </CardTitle>
                    </CardHeader>
                    <CardContent className="flex flex-col gap-3">
                        <label className="grid gap-1.5 text-sm">
                            <span className="font-medium">Title</span>
                            <Input
                                value={form.title}
                                onChange={(event) =>
                                    updateForm({ title: event.target.value })
                                }
                            />
                        </label>
                        <label className="grid gap-1.5 text-sm">
                            <span className="font-medium">Slug</span>
                            <Input
                                value={form.slug}
                                onChange={(event) =>
                                    updateForm({ slug: event.target.value })
                                }
                            />
                        </label>
                        <label className="grid gap-1.5 text-sm">
                            <span className="font-medium">Description</span>
                            <textarea
                                value={form.description}
                                onChange={(event) =>
                                    updateForm({
                                        description: event.target.value,
                                    })
                                }
                                className="border-input focus-visible:border-ring focus-visible:ring-ring/50 min-h-20 resize-none rounded-lg border bg-transparent px-2.5 py-2 text-sm transition-colors outline-none focus-visible:ring-3"
                            />
                        </label>
                        <label className="grid gap-1.5 text-sm">
                            <span className="font-medium">Cover</span>
                            <select
                                value={form.coverPhotoId ?? ""}
                                onChange={(event) =>
                                    updateForm({
                                        coverPhotoId:
                                            event.target.value || null,
                                    })
                                }
                                className="border-input focus-visible:border-ring focus-visible:ring-ring/50 bg-background h-8 rounded-lg border px-2.5 text-sm transition-colors outline-none focus-visible:ring-3"
                            >
                                <option value="">Auto</option>
                                {selectedPhotos.map((photo, index) => (
                                    <option key={photo.id} value={photo.id}>
                                        {index + 1}. {getPhotoLabel(photo)}
                                    </option>
                                ))}
                            </select>
                        </label>
                        <label className="flex items-center gap-2 text-sm">
                            <Checkbox
                                checked={form.isPublished}
                                onCheckedChange={(value) =>
                                    updateForm({ isPublished: Boolean(value) })
                                }
                            />
                            <span className="font-medium">Published</span>
                        </label>
                        {error && (
                            <p className="text-destructive text-sm">{error}</p>
                        )}
                        <Button
                            disabled={saving || !form.title.trim()}
                            onClick={() => void saveCollection()}
                        >
                            {saving ? (
                                <Loader2Icon className="animate-spin" />
                            ) : (
                                <SaveIcon />
                            )}
                            Save
                        </Button>
                    </CardContent>
                </Card>

                <Card>
                    <CardHeader className="flex-row items-center justify-between">
                        <CardTitle>Picked photos</CardTitle>
                        <Button
                            size="icon-sm"
                            variant="ghost"
                            disabled={refreshing}
                            onClick={() => void refreshPickedPhotos()}
                        >
                            {refreshing ? (
                                <Loader2Icon className="animate-spin" />
                            ) : (
                                <RefreshCwIcon />
                            )}
                        </Button>
                    </CardHeader>
                    <CardContent>
                        <div className="grid max-h-130 grid-cols-3 gap-2 overflow-y-auto pr-1">
                            {pickedPhotos.map((photo) => {
                                const selected = selectedPhotoIds.has(photo.id);

                                return (
                                    <button
                                        key={photo.id}
                                        type="button"
                                        className="group bg-muted hover:border-primary focus-visible:border-ring focus-visible:ring-ring/50 relative overflow-hidden rounded-md border text-left transition-colors outline-none focus-visible:ring-3"
                                        onClick={() => togglePhoto(photo.id)}
                                    >
                                        <span className="block aspect-3/4">
                                            {/* eslint-disable-next-line @next/next/no-img-element */}
                                            <img
                                                src={getPhotoUrl(photo)}
                                                alt={getPhotoLabel(photo)}
                                                className="size-full object-cover transition-transform group-hover:scale-[1.03]"
                                            />
                                        </span>
                                        <span className="absolute top-1.5 left-1.5">
                                            <Checkbox
                                                checked={selected}
                                                aria-label="Select photo"
                                                tabIndex={-1}
                                            />
                                        </span>
                                        {form.coverPhotoId === photo.id && (
                                            <Badge className="absolute right-1.5 bottom-1.5">
                                                Cover
                                            </Badge>
                                        )}
                                    </button>
                                );
                            })}
                            {pickedPhotos.length === 0 && (
                                <div className="text-muted-foreground col-span-3 flex h-32 items-center justify-center text-sm">
                                    No picked photos.
                                </div>
                            )}
                        </div>
                    </CardContent>
                </Card>
            </aside>
        </main>
    );
}
