"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
  Banknote,
  Landmark,
  CreditCard,
  Globe,
  Mail,
  MapPin,
  Pencil,
  Phone,
  Plus,
  Search,
  Send,
  Smartphone,
  Trash2,
  User,
  Users,
  LayoutGrid,
} from "lucide-react";
import { Container } from "@/components/common/Container";
import { Card, CardContent } from "@/components/common/Card";
import { Button, ButtonLink } from "@/components/common/Button";
import { RecipientCardSkeleton } from "@/components/common/Skeleton";
import { EmptyState } from "@/components/app/EmptyState";
import { Modal } from "@/components/app/Modal";
import { recipientEditHref } from "@/constants/routes";
import { useBeneficiariesInfinite, useDeleteBeneficiary } from "@/hooks/queries/useBeneficiaries";
import { useTranslation } from "@/hooks/useTranslation";
import { cn } from "@/lib/utils";
import { COUNTRIES } from "@/data/countries";
import type { ApiBeneficiary } from "@/api/beneficiary.api";

type MethodFilter = "all" | "bank" | "cash" | "mobile";

function mapMethod(method: string): "bank" | "cash" | "mobile" {
  const m = method.toLowerCase();
  if (m.includes("bank")) return "bank";
  if (m.includes("mobile")) return "mobile";
  return "cash";
}

function methodIcon(m: "bank" | "cash" | "mobile") {
  return m === "bank" ? Landmark : m === "cash" ? Banknote : Smartphone;
}

function buildName(b: ApiBeneficiary): string {
  return [b.first_name, b.middle_name, b.last_name].filter(Boolean).join(" ");
}

export default function RecipientsPage() {
  const { t } = useTranslation();
  const [search, setSearch] = useState("");
  const [filter, setFilter] = useState<MethodFilter>("all");

  const { data, isLoading, isFetchingNextPage, hasNextPage, fetchNextPage } =
    useBeneficiariesInfinite({
      perPage: 9,
      search,
      method: filter,
    });
  const deleteMutation = useDeleteBeneficiary();

  const [toDelete, setToDelete] = useState<ApiBeneficiary | null>(null);
  const [toView, setToView] = useState<ApiBeneficiary | null>(null);

  const pages = data?.pages;
  const filtered = useMemo(() => {
    if (!pages) return [];
    return pages.flatMap((p) => p.beneficiaries);
  }, [pages]);

  const sentinelRef = useRef<HTMLDivElement | null>(null);

  const handleFetchNextPage = useCallback(() => {
    if (hasNextPage && !isFetchingNextPage) {
      fetchNextPage();
    }
  }, [hasNextPage, isFetchingNextPage, fetchNextPage]);

  useEffect(() => {
    if (!hasNextPage || isFetchingNextPage) return;
    const el = sentinelRef.current;
    if (!el) return;

    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0]?.isIntersecting) {
          handleFetchNextPage();
        }
      },
      { threshold: 0.1, rootMargin: "150px" },
    );

    observer.observe(el);
    return () => observer.disconnect();
  }, [hasNextPage, isFetchingNextPage, handleFetchNextPage]);

  async function confirmDelete() {
    if (!toDelete) return;
    await deleteMutation.mutateAsync(toDelete.id);
    setToDelete(null);
  }

  return (
    <Container className="max-w-full space-y-6">
      <header className="flex flex-wrap items-end justify-between gap-4">
        <div>
          <h1 className="text-2xl font-bold text-slate-900 dark:text-white sm:text-3xl">
            {t("app.recipients.title")}
          </h1>
          <p className="mt-1 text-sm text-slate-600 dark:text-slate-300">
            {t("app.recipients.subtitle")}
          </p>
        </div>
        <ButtonLink href="/recipients/new">
          <Plus className="h-4 w-4" />
          {t("app.recipients.add")}
        </ButtonLink>
      </header>

      {(isLoading || search.trim() !== "" || filter !== "all" || filtered.length > 0) && (
        <div className="flex flex-wrap gap-3">
          <div className="relative min-w-[240px] flex-1">
            <Search className="pointer-events-none absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400" />
            <input
              type="search"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder={t("app.recipients.search")}
              className="h-11 w-full rounded-2xl border border-slate-200 bg-white ps-9 pe-4 text-sm outline-none focus:border-brand-400 dark:border-slate-700 dark:bg-slate-900 dark:text-white"
            />
          </div>
          <div className="scrollbar-hide w-full overflow-x-auto sm:w-auto">
            <div
              role="tablist"
              className="flex w-max min-w-full gap-1 rounded-2xl border border-slate-200 bg-slate-50/80 p-1.5 dark:border-slate-800 dark:bg-slate-950/50 backdrop-blur-sm"
            >
              {(
                [
                  { v: "all", labelKey: "app.recipients.filterAll", icon: LayoutGrid },
                  { v: "bank", labelKey: "app.recipients.filterBank", icon: Landmark },
                  { v: "cash", labelKey: "app.recipients.filterCash", icon: Banknote },
                  { v: "mobile", labelKey: "app.recipients.filterMobile", icon: Smartphone },
                ] as const
              ).map((f) => {
                const Icon = f.icon;
                const isActive = filter === f.v;
                return (
                  <button
                    key={f.v}
                    type="button"
                    role="tab"
                    aria-selected={isActive}
                    onClick={() => setFilter(f.v)}
                    className={cn(
                      "inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-xl px-3 py-1.5 text-[length:var(--text-sm-fixed)] font-medium transition-all duration-200 border border-transparent",
                      isActive
                        ? "bg-white text-brand-600 shadow-sm border-slate-200/50 dark:bg-slate-900 dark:text-brand-400 dark:border-slate-800"
                        : "text-slate-500 hover:text-slate-900 hover:bg-white/50 dark:text-slate-400 dark:hover:text-white dark:hover:bg-slate-900/30",
                    )}
                  >
                    <Icon className="h-3.5 w-3.5" />
                    <span>{t(f.labelKey)}</span>
                  </button>
                );
              })}
            </div>
          </div>
        </div>
      )}

      {isLoading ? (
        <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
          <RecipientCardSkeleton />
          <RecipientCardSkeleton />
          <RecipientCardSkeleton />
          <RecipientCardSkeleton />
          <RecipientCardSkeleton />
          <RecipientCardSkeleton />
        </div>
      ) : !search.trim() && filter === "all" && filtered.length === 0 ? (
        <EmptyState
          icon={Users}
          title={t("app.recipients.empty")}
          body={t("app.recipients.emptyBody")}
          action={
            <ButtonLink href="/recipients/new">
              <Plus className="h-4 w-4" />
              {t("app.recipients.addFirst")}
            </ButtonLink>
          }
        />
      ) : filtered.length === 0 ? (
        <EmptyState
          icon={Search}
          title={t("app.recipients.noResults") !== "app.recipients.noResults" ? t("app.recipients.noResults") : "No recipients found"}
          body={t("app.recipients.noResultsBody") !== "app.recipients.noResultsBody" ? t("app.recipients.noResultsBody") : "We couldn't find any recipients matching your search or filter criteria. Try adjusting your filters."}
          className="py-12"
        />
      ) : (
        <>
          <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
            {filtered.map((b) => {
              const name = buildName(b);
              const method = mapMethod(b.method);
              const Icon = methodIcon(method);
              const country = COUNTRIES.find(
                (c) => c.name.toLowerCase() === b.country.toLowerCase(),
              );
              const initials = name
                .split(" ")
                .map((p) => p.charAt(0))
                .slice(0, 2)
                .join("");
              return (
                <Card key={b.id} interactive className="flex flex-col">
                  <CardContent className="flex flex-1 flex-col">
                    <div className="flex items-start gap-3">
                      <span
                        aria-hidden
                        className="grid h-12 w-12 place-items-center rounded-full bg-gradient-to-br from-brand-500 to-accent-500 text-sm font-bold text-white"
                      >
                        {initials}
                      </span>
                      <div className="min-w-0 flex-1">
                        <button
                          type="button"
                          onClick={() => setToView(b)}
                          className="truncate text-base font-bold text-slate-900 hover:text-brand-700 dark:text-white dark:hover:text-brand-300"
                        >
                          {name}
                        </button>
                        <div className="mt-0.5 flex items-center gap-2">
                          <div className="flex items-center text-xs text-slate-500 dark:text-slate-400">
                            {country && (
                              <img
                                src={`https://flagcdn.com/w40/${country.code.toLowerCase()}.png`}
                                alt={country.name}
                                className="me-1.5 h-3.5 w-5 shrink-0 rounded-xs object-cover shadow-sm border border-slate-100 dark:border-slate-800"
                                aria-hidden
                              />
                            )}
                            <span>{b.country}</span>
                          </div>
                          <span
                            className={cn(
                              "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-2xs font-semibold uppercase tracking-wider border",
                              method === "bank" && "bg-blue-50 text-blue-700 border-blue-100 dark:bg-blue-500/10 dark:text-blue-400 dark:border-blue-500/20",
                              method === "cash" && "bg-emerald-50 text-emerald-700 border-emerald-100 dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20",
                              method === "mobile" && "bg-amber-50 text-amber-700 border-amber-100 dark:bg-amber-500/10 dark:text-amber-400 dark:border-amber-500/20"
                            )}
                            aria-label={method}
                          >
                            <Icon className="h-3 w-3" />
                            {method}
                          </span>
                        </div>
                      </div>
                    </div>
                    <p className="mt-4 text-xs text-slate-500 dark:text-slate-400">
                      {b.address || "—"}
                    </p>
                    <div className="mt-4 flex flex-wrap gap-2">
                      <ButtonLink href="/send" size="sm">
                        <Send className="h-3.5 w-3.5 rtl:-scale-x-100" />
                        {t("app.recipients.actionSend")}
                      </ButtonLink>
                      <ButtonLink href={recipientEditHref(b.id)} prefetch={false} size="sm" variant="outline">
                        <Pencil className="h-3.5 w-3.5" />
                        {t("app.recipients.actionEdit")}
                      </ButtonLink>
                      <Button
                        size="sm"
                        variant="ghost"
                        onClick={() => setToDelete(b)}
                        className="text-rose-600 hover:bg-rose-50 dark:text-rose-300 dark:hover:bg-rose-500/10"
                      >
                        <Trash2 className="h-3.5 w-3.5" />
                        {t("app.recipients.actionDelete")}
                      </Button>
                    </div>
                  </CardContent>
                </Card>
              );
            })}
            {isFetchingNextPage && (
              <>
                <RecipientCardSkeleton />
                <RecipientCardSkeleton />
                <RecipientCardSkeleton />
              </>
            )}
          </div>

          <div ref={sentinelRef} className="h-4 w-full" aria-hidden />

          {hasNextPage && !isFetchingNextPage && (
            <div className="flex justify-center pt-2">
              <Button
                type="button"
                variant="outline"
                onClick={handleFetchNextPage}
                className="text-xs font-semibold"
              >
                Load more recipients
              </Button>
            </div>
          )}
        </>
      )}

      <Modal
        open={!!toView}
        onClose={() => setToView(null)}
        title="Recipient Details"
      >
        {toView && (
          <ul className="space-y-4">
            {(
              [
                { icon: User, label: "Name", value: buildName(toView) },
                { icon: Mail, label: "Email", value: toView.email },
                { icon: Globe, label: "Country", value: toView.country },
                {
                  icon: MapPin,
                  label: "City & State",
                  value: [toView.city, toView.state].filter(Boolean).join(", "),
                },
                { icon: Phone, label: "Phone", value: toView.phone },
                {
                  icon: Landmark,
                  label: "Method Name",
                  value: toView.bank_name || toView.mobile_name || toView.method,
                },
                {
                  icon: CreditCard,
                  label: "Account Number",
                  value: toView.iban_number || toView.account_number,
                },
              ] as const
            ).map(({ icon: Icon, label, value }) => (
              <li key={label} className="flex items-center gap-3">
                <span className="grid h-9 w-9 shrink-0 place-items-center rounded-full border border-slate-200 dark:border-slate-700">
                  <Icon className="h-4 w-4 text-brand-600 dark:text-brand-400" />
                </span>
                <div>
                  <p className="text-xs text-slate-500 dark:text-slate-400">{label}</p>
                  <p className="text-sm font-medium text-slate-900 dark:text-white">
                    {value || "—"}
                  </p>
                </div>
              </li>
            ))}
          </ul>
        )}
      </Modal>

      <Modal
        open={!!toDelete}
        onClose={() => !deleteMutation.isPending && setToDelete(null)}
        title={t("app.recipients.confirmDeleteTitle")}
        footer={
          <>
            <Button
              type="button"
              variant="outline"
              onClick={() => setToDelete(null)}
              disabled={deleteMutation.isPending}
            >
              {t("app.recipients.cancel")}
            </Button>
            <Button
              type="button"
              onClick={confirmDelete}
              loading={deleteMutation.isPending}
              className="bg-rose-600 hover:bg-rose-700"
            >
              {t("app.recipients.confirmDelete")}
            </Button>
          </>
        }
      >
        {toDelete && (
          <p>
            {t("app.recipients.confirmDeleteBody").replace("{name}", buildName(toDelete))}
          </p>
        )}
      </Modal>
    </Container>
  );
}
