"use client";

import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
import type { ComponentType } from "react";
import {
  Bike,
  CarFront,
  Edit3,
  GripVertical,
  Layers3,
  Loader2,
  Plus,
  Trash2,
  X,
} from "lucide-react";
import { AdminGuard } from "@/components/admin/AdminGuard";
import { AdminShell } from "@/components/admin/AdminShell";
import { adminRequest, type AdminVehicleTier } from "@/lib/admin-api";

type VehicleType = AdminVehicleTier["vehicleType"];

const vehicleTypeMeta: Record<
  VehicleType,
  {
    label: string;
    icon: ComponentType<{ className?: string }>;
  }
> = {
  car: {
    label: "Car tiers",
    icon: CarFront,
  },
  bike: {
    label: "Bike tiers",
    icon: Bike,
  },
  "ev-car": {
    label: "EV Car tiers",
    icon: CarFront,
  },
  "ev-bike": {
    label: "EV Bike tiers",
    icon: Bike,
  },
};

const vehicleTypes: VehicleType[] = ["car", "bike", "ev-car", "ev-bike"];

export default function AdminVehicleTiersPage() {
  const [tiers, setTiers] = useState<AdminVehicleTier[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);
  const [isDeletingId, setIsDeletingId] = useState<number | null>(null);
  const [errorMessage, setErrorMessage] = useState("");
  const [activeVehicleType, setActiveVehicleType] = useState<VehicleType>("car");
  const [addingVehicleType, setAddingVehicleType] = useState<VehicleType | null>(null);
  const [addName, setAddName] = useState("");
  const [editingTier, setEditingTier] = useState<AdminVehicleTier | null>(null);
  const [editName, setEditName] = useState("");
  const [pendingDeleteTier, setPendingDeleteTier] = useState<AdminVehicleTier | null>(null);
  const [draggedTierId, setDraggedTierId] = useState<number | null>(null);
  const [dragOverTierId, setDragOverTierId] = useState<number | null>(null);

  const loadTiers = useCallback(async () => {
    setIsLoading(true);
    setErrorMessage("");

    try {
      const data = await adminRequest<{ tiers: AdminVehicleTier[] }>("/api/admin/vehicle-tiers");
      setTiers(data.tiers);
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "Could not load vehicle tiers");
    } finally {
      setIsLoading(false);
    }
  }, []);

  useEffect(() => {
    loadTiers();
  }, [loadTiers]);

  useEffect(() => {
    if (!addingVehicleType && !editingTier && !pendingDeleteTier) {
      return;
    }

    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";

    return () => {
      document.body.style.overflow = previousOverflow;
    };
  }, [addingVehicleType, editingTier, pendingDeleteTier]);

  function getNextTierLevel(vehicleType: VehicleType) {
    return (
      tiers
        .filter((tier) => tier.vehicleType === vehicleType)
        .reduce((highest, tier) => Math.max(highest, tier.tierLevel), 0) + 1
    );
  }

  function openAddModal(vehicleType: VehicleType) {
    setAddingVehicleType(vehicleType);
    setAddName("");
    setErrorMessage("");
  }

  async function createTier(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();

    if (!addingVehicleType) {
      return;
    }

    setIsSaving(true);
    setErrorMessage("");

    try {
      await adminRequest("/api/admin/vehicle-tiers", {
        method: "POST",
        body: JSON.stringify({
          vehicleType: addingVehicleType,
          tierLevel: getNextTierLevel(addingVehicleType),
          name: addName.trim(),
        }),
      });

      setAddingVehicleType(null);
      setAddName("");
      await loadTiers();
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "Could not create vehicle tier");
    } finally {
      setIsSaving(false);
    }
  }

  function openEditModal(tier: AdminVehicleTier) {
    setEditingTier(tier);
    setEditName(tier.name);
    setErrorMessage("");
  }

  async function saveTier(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();

    if (!editingTier) {
      return;
    }

    setIsSaving(true);
    setErrorMessage("");

    try {
      await adminRequest(`/api/admin/vehicle-tiers/${editingTier.id}`, {
        method: "PUT",
        body: JSON.stringify({ name: editName.trim() }),
      });

      setEditingTier(null);
      setEditName("");
      await loadTiers();
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "Could not update vehicle tier");
    } finally {
      setIsSaving(false);
    }
  }

  async function deleteTier(tier: AdminVehicleTier) {
    setIsDeletingId(tier.id);
    setErrorMessage("");

    try {
      await adminRequest(`/api/admin/vehicle-tiers/${tier.id}`, {
        method: "DELETE",
      });

      setPendingDeleteTier(null);
      await loadTiers();
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "Could not delete vehicle tier");
    } finally {
      setIsDeletingId(null);
    }
  }

  async function swapTierPositions(sourceId: number, targetId: number) {
    if (sourceId === targetId) {
      setDraggedTierId(null);
      setDragOverTierId(null);
      return;
    }

    const sourceTier = tiers.find((tier) => tier.id === sourceId);
    const targetTier = tiers.find((tier) => tier.id === targetId);

    if (!sourceTier || !targetTier || sourceTier.vehicleType !== targetTier.vehicleType) {
      setDraggedTierId(null);
      setDragOverTierId(null);
      return;
    }

    setErrorMessage("");
    setTiers((currentTiers) =>
      currentTiers
        .map((tier) => {
          if (tier.id === sourceId) {
            return { ...tier, tierLevel: targetTier.tierLevel };
          }

          if (tier.id === targetId) {
            return { ...tier, tierLevel: sourceTier.tierLevel };
          }

          return tier;
        })
        .sort((a, b) => a.vehicleType.localeCompare(b.vehicleType) || a.tierLevel - b.tierLevel),
    );

    try {
      await adminRequest("/api/admin/vehicle-tiers/swap", {
        method: "PATCH",
        body: JSON.stringify({ sourceId, targetId }),
      });
      await loadTiers();
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : "Could not swap vehicle tiers");
      await loadTiers();
    } finally {
      setDraggedTierId(null);
      setDragOverTierId(null);
    }
  }

  const groupedTiers = useMemo(
    () =>
      Object.fromEntries(
        vehicleTypes.map((vehicleType) => [
          vehicleType,
          tiers
            .filter((tier) => tier.vehicleType === vehicleType)
            .sort((a, b) => a.tierLevel - b.tierLevel),
        ]),
      ) as Record<VehicleType, AdminVehicleTier[]>,
    [tiers],
  );

  return (
    <AdminGuard>
      <AdminShell
        title="Vehicle tiers"
        lead="Manage the tier names used to classify cars and bikes."
      >
        <section className="space-y-5">
          <div className="rounded-lg border border-border bg-white p-5 shadow-sm">
            <div className="flex items-center gap-3">
              <div className="grid h-11 w-11 place-items-center rounded-md bg-primary/10 text-primary">
                <Layers3 className="h-5 w-5" />
              </div>
              <div>
                <p className="text-xs font-black uppercase tracking-[0.16em] text-muted-foreground">
                  Tier setup
                </p>
                <h2 className="mt-1 text-xl font-black tracking-tight text-foreground">
                  Add, edit, and remove tiers for cars and bikes
                </h2>
              </div>
            </div>
          </div>

          {errorMessage ? (
            <div className="rounded-lg border border-primary/20 bg-primary/5 p-4 text-sm font-bold text-primary">
              {errorMessage}
            </div>
          ) : null}

          {isLoading ? (
            <div className="flex min-h-48 items-center justify-center rounded-lg border border-border bg-white">
              <Loader2 className="h-6 w-6 animate-spin text-primary" />
            </div>
          ) : (
            <>
              <div className="flex gap-2 overflow-x-auto rounded-lg border border-border bg-slate-50 p-2">
                {vehicleTypes.map((vehicleType) => (
                  <button
                    key={vehicleType}
                    type="button"
                    onClick={() => setActiveVehicleType(vehicleType)}
                    className={`w-36 shrink-0 rounded-md border px-3 py-2 text-sm font-black transition ${
                      activeVehicleType === vehicleType
                        ? "border-primary bg-primary text-primary-foreground shadow-sm"
                        : "border-slate-300 bg-white text-muted-foreground hover:border-slate-400 hover:text-foreground"
                    }`}
                  >
                    {vehicleTypeMeta[vehicleType].label}
                  </button>
                ))}
              </div>
              <TierTable
                vehicleType={activeVehicleType}
                tiers={groupedTiers[activeVehicleType]}
                draggedTierId={draggedTierId}
                dragOverTierId={dragOverTierId}
                onAdd={openAddModal}
                onEdit={openEditModal}
                onDelete={setPendingDeleteTier}
                onDragStart={setDraggedTierId}
                onDragOver={setDragOverTierId}
                onDragEnd={() => {
                  setDraggedTierId(null);
                  setDragOverTierId(null);
                }}
                onDrop={swapTierPositions}
              />
            </>
          )}
        </section>

        {addingVehicleType ? (
          <div className="fixed inset-0 z-[70] grid place-items-center bg-slate-950/45 px-4">
            <div className="w-full max-w-md rounded-lg border border-border bg-white p-5 shadow-2xl">
              <div className="flex items-start justify-between gap-4">
                <div>
                  <p className="text-xs font-black uppercase tracking-[0.16em] text-primary">
                    Add tier
                  </p>
                  <h2 className="mt-1 text-xl font-black tracking-tight text-foreground">
                    {vehicleTypeMeta[addingVehicleType].label}
                  </h2>
                </div>
                <button
                  type="button"
                  onClick={() => setAddingVehicleType(null)}
                  className="grid h-9 w-9 place-items-center rounded-md text-muted-foreground hover:bg-slate-100"
                  aria-label="Close add tier dialog"
                >
                  <X className="h-5 w-5" />
                </button>
              </div>

              <form onSubmit={createTier} className="mt-5 space-y-4">
                <label className="block">
                  <span className="text-xs font-black uppercase tracking-[0.14em] text-muted-foreground">
                    Tier name
                  </span>
                  <input
                    value={addName}
                    onChange={(event) => setAddName(event.target.value)}
                    className="mt-2 h-11 w-full rounded-md border border-input bg-white px-3 text-sm font-bold text-foreground outline-none transition focus:border-primary focus:ring-4 focus:ring-primary/10"
                    placeholder="Tier name"
                    required
                    maxLength={80}
                  />
                </label>

                <div className="flex justify-end gap-2">
                  <button
                    type="button"
                    onClick={() => setAddingVehicleType(null)}
                    className="h-10 rounded-md border border-border px-4 text-sm font-black text-muted-foreground transition hover:bg-slate-100 hover:text-foreground"
                  >
                    Cancel
                  </button>
                  <button
                    type="submit"
                    disabled={isSaving}
                    className="inline-flex h-10 items-center justify-center gap-2 rounded-md bg-primary px-4 text-sm font-black text-primary-foreground transition hover:opacity-95 disabled:cursor-not-allowed disabled:opacity-60"
                  >
                    {isSaving ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
                    Add tier
                  </button>
                </div>
              </form>
            </div>
          </div>
        ) : null}

        {editingTier ? (
          <div className="fixed inset-0 z-[70] grid place-items-center bg-slate-950/45 px-4">
            <div className="w-full max-w-md rounded-lg border border-border bg-white p-5 shadow-2xl">
              <div className="flex items-start justify-between gap-4">
                <div>
                  <p className="text-xs font-black uppercase tracking-[0.16em] text-primary">
                    Edit tier
                  </p>
                  <h2 className="mt-1 text-xl font-black tracking-tight text-foreground">
                    {vehicleTypeMeta[editingTier.vehicleType].label} level {editingTier.tierLevel}
                  </h2>
                </div>
                <button
                  type="button"
                  onClick={() => setEditingTier(null)}
                  className="grid h-9 w-9 place-items-center rounded-md text-muted-foreground hover:bg-slate-100"
                  aria-label="Close edit tier dialog"
                >
                  <X className="h-5 w-5" />
                </button>
              </div>

              <form onSubmit={saveTier} className="mt-5 space-y-4">
                <label className="block">
                  <span className="text-xs font-black uppercase tracking-[0.14em] text-muted-foreground">
                    Tier name
                  </span>
                  <input
                    value={editName}
                    onChange={(event) => setEditName(event.target.value)}
                    className="mt-2 h-11 w-full rounded-md border border-input bg-white px-3 text-sm font-bold text-foreground outline-none transition focus:border-primary focus:ring-4 focus:ring-primary/10"
                    placeholder="Tier name"
                    required
                    maxLength={80}
                  />
                </label>

                <div className="flex justify-end gap-2">
                  <button
                    type="button"
                    onClick={() => setEditingTier(null)}
                    className="h-10 rounded-md border border-border px-4 text-sm font-black text-muted-foreground transition hover:bg-slate-100 hover:text-foreground"
                  >
                    Cancel
                  </button>
                  <button
                    type="submit"
                    disabled={isSaving}
                    className="inline-flex h-10 items-center justify-center gap-2 rounded-md bg-primary px-4 text-sm font-black text-primary-foreground transition hover:opacity-95 disabled:cursor-not-allowed disabled:opacity-60"
                  >
                    {isSaving ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
                    Save tier
                  </button>
                </div>
              </form>
            </div>
          </div>
        ) : null}

        {pendingDeleteTier ? (
          <div className="fixed inset-0 z-[70] grid place-items-center bg-slate-950/45 px-4">
            <div className="w-full max-w-sm rounded-lg border border-border bg-white p-5 shadow-2xl">
              <div className="grid h-11 w-11 place-items-center rounded-md bg-primary/10 text-primary">
                <Trash2 className="h-5 w-5" />
              </div>
              <h2 className="mt-4 text-xl font-black tracking-tight text-foreground">
                Delete tier?
              </h2>
              <p className="mt-2 text-sm leading-6 text-muted-foreground">
                This will remove {pendingDeleteTier.name} from{" "}
                {vehicleTypeMeta[pendingDeleteTier.vehicleType].label.toLowerCase()}.
              </p>
              <div className="mt-5 flex justify-end gap-2">
                <button
                  type="button"
                  onClick={() => setPendingDeleteTier(null)}
                  className="h-10 rounded-md border border-border px-4 text-sm font-black text-muted-foreground transition hover:bg-slate-100 hover:text-foreground"
                >
                  Cancel
                </button>
                <button
                  type="button"
                  onClick={() => deleteTier(pendingDeleteTier)}
                  disabled={isDeletingId === pendingDeleteTier.id}
                  className="inline-flex h-10 items-center justify-center gap-2 rounded-md bg-primary px-4 text-sm font-black text-primary-foreground transition hover:opacity-95 disabled:cursor-not-allowed disabled:opacity-60"
                >
                  {isDeletingId === pendingDeleteTier.id ? (
                    <Loader2 className="h-4 w-4 animate-spin" />
                  ) : null}
                  Delete
                </button>
              </div>
            </div>
          </div>
        ) : null}
      </AdminShell>
    </AdminGuard>
  );
}

function TierTable({
  vehicleType,
  tiers,
  draggedTierId,
  dragOverTierId,
  onAdd,
  onEdit,
  onDelete,
  onDragStart,
  onDragOver,
  onDragEnd,
  onDrop,
}: {
  vehicleType: VehicleType;
  tiers: AdminVehicleTier[];
  draggedTierId: number | null;
  dragOverTierId: number | null;
  onAdd: (vehicleType: VehicleType) => void;
  onEdit: (tier: AdminVehicleTier) => void;
  onDelete: (tier: AdminVehicleTier) => void;
  onDragStart: (tierId: number) => void;
  onDragOver: (tierId: number) => void;
  onDragEnd: () => void;
  onDrop: (sourceId: number, targetId: number) => void;
}) {
  const meta = vehicleTypeMeta[vehicleType];
  const Icon = meta.icon;

  return (
    <article className="overflow-hidden rounded-lg border border-border bg-white shadow-sm">
      <div className="flex items-center justify-between gap-4 border-b border-border p-5">
        <div>
          <p className="text-xs font-black uppercase tracking-[0.16em] text-muted-foreground">
            {vehicleType}
          </p>
          <h2 className="mt-1 text-xl font-black tracking-tight text-foreground">{meta.label}</h2>
        </div>
        <div className="flex items-center gap-2">
          <button
            type="button"
            onClick={() => onAdd(vehicleType)}
            disabled={tiers.length >= 6}
            className="inline-flex h-10 items-center justify-center gap-2 rounded-md bg-primary px-3 text-sm font-black text-primary-foreground transition hover:opacity-95 disabled:cursor-not-allowed disabled:opacity-50"
          >
            <Plus className="h-4 w-4" />
            Add
          </button>
          <div className="grid h-11 w-11 place-items-center rounded-md bg-primary/10 text-primary">
            <Icon className="h-5 w-5" />
          </div>
        </div>
      </div>

      <div className="overflow-x-auto">
        <table className="w-full min-w-[360px] text-left">
          <thead className="bg-slate-50 text-xs font-black uppercase tracking-[0.14em] text-muted-foreground">
            <tr>
              <th className="px-5 py-3">Level</th>
              <th className="px-5 py-3">Tier name</th>
              <th className="px-5 py-3 text-right">Actions</th>
            </tr>
          </thead>
          <tbody className="divide-y divide-border text-sm">
            {tiers.map((tier) => {
              const isDragging = draggedTierId === tier.id;
              const isDragTarget = dragOverTierId === tier.id && !isDragging;

              return (
                <tr
                  key={tier.id}
                  draggable
                  onDragStart={(event) => {
                    onDragStart(tier.id);
                    event.dataTransfer.effectAllowed = "move";
                    event.dataTransfer.setData("text/plain", String(tier.id));
                  }}
                  onDragOver={(event) => {
                    event.preventDefault();
                    event.dataTransfer.dropEffect = "move";
                    onDragOver(tier.id);
                  }}
                  onDrop={(event) => {
                    event.preventDefault();
                    const sourceId = Number(
                      event.dataTransfer.getData("text/plain") || draggedTierId,
                    );

                    if (Number.isFinite(sourceId)) {
                      onDrop(sourceId, tier.id);
                    }
                  }}
                  onDragEnd={onDragEnd}
                  className={`${isDragging ? "opacity-50" : ""} ${isDragTarget ? "bg-primary/5" : ""}`}
                >
                  <td className="px-5 py-4">
                    <div className="flex items-center gap-2">
                      <GripVertical className="h-4 w-4 text-muted-foreground" />
                      <span className="inline-grid h-8 w-8 place-items-center rounded-md bg-foreground text-sm font-black text-background">
                        {tier.tierLevel}
                      </span>
                    </div>
                  </td>
                  <td className="px-5 py-4 text-base font-black text-foreground">{tier.name}</td>
                  <td className="px-5 py-4">
                    <div className="flex justify-end gap-2">
                      <button
                        type="button"
                        onClick={() => onEdit(tier)}
                        className="grid h-9 w-9 place-items-center rounded-md border border-border text-muted-foreground transition hover:bg-slate-100 hover:text-foreground"
                        aria-label={`Edit ${tier.name}`}
                      >
                        <Edit3 className="h-4 w-4" />
                      </button>
                      <button
                        type="button"
                        onClick={() => onDelete(tier)}
                        className="grid h-9 w-9 place-items-center rounded-md border border-primary/20 text-primary transition hover:bg-primary hover:text-primary-foreground"
                        aria-label={`Delete ${tier.name}`}
                      >
                        <Trash2 className="h-4 w-4" />
                      </button>
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </article>
  );
}
