"use client";

import { useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { ChevronDown, Receipt, Search } from "lucide-react";
import ReactSelect, { type DropdownIndicatorProps, components } from "react-select";
import { Container } from "@/components/common/Container";
import { Card, CardContent } from "@/components/common/Card";
import { StatusBadge } from "@/components/app/StatusBadge";
import { Pagination } from "@/components/app/Pagination";
import { EmptyState } from "@/components/app/EmptyState";
import { TransferSuccessModal } from "@/components/app/TransferSuccessModal";
import { transactionDetailHref } from "@/constants/routes";
import { useTransactions } from "@/hooks/queries/useTransactions";
import { useTranslation } from "@/hooks/useTranslation";
import { cn } from "@/lib/utils";
import { mapTransactionStatus } from "@/lib/transactionStatus";
import type { ApiRemittanceData } from "@/api/transaction.api";
import type { TransferStatus } from "@/types";

interface SuccessRedirectData {
  trxId: string;
  shareLink: string;
  downloadLink: string;
}

type StatusFilter = TransferStatus | "all";

const PAGE_SIZE = 8;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function StatusDropdownIndicator(props: DropdownIndicatorProps<any>) {
  return (
    <components.DropdownIndicator {...props}>
      <ChevronDown
        className={cn(
          "h-4 w-4 text-slate-400 transition-transform duration-200",
          props.selectProps.menuIsOpen && "rotate-180",
        )}
      />
    </components.DropdownIndicator>
  );
}

function buildName(rd: ApiRemittanceData): string {
  return [rd.first_name, rd.middle_name, rd.last_name].filter(Boolean).join(" ");
}

// These URLs come straight off the query string — attacker-controlled (anyone can
// craft `?download_link=javascript:...`). Reject anything but http/https before it
// ever reaches an href or navigator.share({ url }).
function isSafeHttpUrl(value: string): boolean {
  try {
    const parsed = new URL(value, window.location.origin);
    return parsed.protocol === "http:" || parsed.protocol === "https:";
  } catch {
    return false;
  }
}

export default function TransactionsPage() {
  const { t } = useTranslation();
  const { data, isLoading } = useTransactions();

  const [search, setSearch] = useState("");
  const [statusFilter, setStatusFilter] = useState<StatusFilter>("all");
  const [page, setPage] = useState(1);
  const [successRedirect, setSuccessRedirect] = useState<SuccessRedirectData | null>(null);

  // A hosted payment gateway redirects back here (success_url) with these params.
  // Deliberately NOT stripped here — leave them in the URL until the user actually
  // dismisses the modal (dismissSuccessRedirect below). If this effect re-runs on a
  // stray remount before that (dev double-mount, router reconciliation, etc.), the
  // modal must still be re-derivable from the URL, or it silently vanishes with no
  // way back — which is exactly what stripping on read caused.
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const trx = params.get("trx");
    const shareLink = params.get("share_link");
    const downloadLink = params.get("download_link");
    if (!trx || !shareLink || !downloadLink) return;
    if (!isSafeHttpUrl(shareLink) || !isSafeHttpUrl(downloadLink)) return;

    setSuccessRedirect({ trxId: trx, shareLink, downloadLink });
  }, []);

  // Only strip the one-time-use params once the user is actually done with the modal —
  // that's when they should land on the plain /transactions URL, not before.
  function dismissSuccessRedirect() {
    setSuccessRedirect(null);
    const clean = new URL(window.location.href);
    clean.searchParams.delete("trx");
    clean.searchParams.delete("share_link");
    clean.searchParams.delete("download_link");
    window.history.replaceState({}, "", clean.toString());
  }

  const statusOptions = useMemo<Array<{ value: StatusFilter; label: string }>>(
    () => [
      { value: "all", label: t("app.transactions.filterAll") },
      { value: "pending", label: t("app.transactions.status.pending") },
      { value: "processing", label: t("app.transactions.status.processing") },
      { value: "in_transit", label: t("app.transactions.status.in_transit") },
      { value: "delivered", label: t("app.transactions.status.delivered") },
      { value: "failed", label: t("app.transactions.status.failed") },
      { value: "cancelled", label: t("app.transactions.status.cancelled") },
    ],
    [t],
  );

  const transactions = useMemo(() => data?.transaction ?? [], [data]);

  const filtered = useMemo(() => {
    const term = search.trim().toLowerCase();
    return transactions.filter((tx) => {
      if (statusFilter !== "all" && mapTransactionStatus(tx.status) !== statusFilter) return false;
      if (term) {
        const name = buildName(tx.remittance_data).toLowerCase();
        if (!tx.trx_id.toLowerCase().includes(term) && !name.includes(term)) return false;
      }
      return true;
    });
  }, [transactions, search, statusFilter]);

  const pageCount = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
  const pageItems = filtered.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
  const safePage = Math.min(page, pageCount);

  return (
    <Container className="max-w-full space-y-6">
      <header>
        <h1 className="text-2xl font-bold text-slate-900 dark:text-white sm:text-3xl">
          {t("app.transactions.title")}
        </h1>
        <p className="mt-1 text-sm text-slate-600 dark:text-slate-300">
          {t("app.transactions.subtitle")}
        </p>
      </header>

      <Card>
        <CardContent>
          <div className="flex flex-wrap gap-3">
            <div className="relative min-w-[260px] 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);
                  setPage(1);
                }}
                placeholder={t("app.transactions.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>
            <ReactSelect
              unstyled
              isSearchable={false}
              components={{ DropdownIndicator: StatusDropdownIndicator }}
              options={statusOptions}
              value={statusOptions.find((o) => o.value === statusFilter) ?? null}
              onChange={(opt) => {
                setStatusFilter(((opt as { value: string } | null)?.value ?? "all") as StatusFilter);
                setPage(1);
              }}
              aria-label={t("app.transactions.filterStatus")}
              classNames={{
                control: () =>
                  "h-11 min-w-[160px] cursor-pointer rounded-2xl border border-slate-200 bg-white px-3 text-sm dark:border-slate-700 dark:bg-slate-900",
                menu: () =>
                  "z-50 mt-1 min-w-[180px] overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg dark:border-slate-700 dark:bg-slate-900",
                option: ({ isFocused, isSelected }) =>
                  cn(
                    "cursor-pointer px-4 py-2 text-sm",
                    isSelected
                      ? "bg-brand-600 text-white"
                      : isFocused
                        ? "bg-slate-100 text-slate-900 dark:bg-slate-800 dark:text-white"
                        : "text-slate-700 dark:text-slate-200",
                  ),
                singleValue: () => "text-slate-900 dark:text-white",
                indicatorsContainer: () => "text-slate-400 dark:text-slate-500",
              }}
            />
          </div>

          {isLoading ? (
            <div className="mt-5 divide-y divide-slate-100 dark:divide-slate-800">
              {[1, 2, 3, 4, 5].map((i) => (
                <div key={i} className="flex items-center gap-4 py-4">
                  <div className="flex-1 space-y-2">
                    <div className="h-4 w-1/3 animate-pulse rounded-md bg-slate-200 dark:bg-slate-700" />
                    <div className="h-3 w-1/4 animate-pulse rounded-md bg-slate-200 dark:bg-slate-700" />
                  </div>
                  <div className="h-6 w-20 animate-pulse rounded-full bg-slate-200 dark:bg-slate-700" />
                </div>
              ))}
            </div>
          ) : filtered.length === 0 ? (
            <EmptyState
              icon={Receipt}
              title={t("app.transactions.empty")}
              body={t("app.transactions.emptyBody")}
              className="mt-5 border-0"
            />
          ) : (
            <div className="-mx-6 mt-5 overflow-x-auto sm:-mx-7">
              <table className="w-full min-w-[720px] table-fixed border-collapse [&_td:first-child]:ps-6 [&_td:last-child]:pe-6 [&_th:first-child]:ps-6 [&_th:last-child]:pe-6 sm:[&_td:first-child]:ps-7 sm:[&_td:last-child]:pe-7 sm:[&_th:first-child]:ps-7 sm:[&_th:last-child]:pe-7">
                <thead>
                  <tr className="border-b border-slate-200 dark:border-slate-800">
                    <th className="w-1/6 whitespace-nowrap px-3 py-4 text-start text-xs font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500">{t("app.transactions.columnRef")}</th>
                    <th className="w-1/6 whitespace-nowrap px-3 py-4 text-start text-xs font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500">{t("app.transactions.columnRecipient")}</th>
                    <th className="w-1/6 whitespace-nowrap px-3 py-4 text-start text-xs font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500">Type</th>
                    <th className="w-1/6 whitespace-nowrap px-3 py-4 text-start text-xs font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500">{t("app.transactions.columnSent")}</th>
                    <th className="w-1/6 whitespace-nowrap px-3 py-4 text-start text-xs font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500">{t("app.transactions.columnAmount")}</th>
                    <th className="w-1/6 whitespace-nowrap px-3 py-4 text-start text-xs font-bold uppercase tracking-wider text-slate-400 dark:text-slate-500">{t("app.transactions.columnStatus")}</th>
                  </tr>
                </thead>
                <tbody className="divide-y divide-slate-100 dark:divide-slate-800">
                  {pageItems.map((tx) => {
                    const rd = tx.remittance_data;
                    const receiverAmount = (
                      parseFloat(rd.send_money) * parseFloat(rd.receiver_ex_rate)
                    ).toFixed(2);
                    return (
                      <tr
                        key={tx.trx_id}
                        className="transition hover:bg-slate-50/70 dark:hover:bg-slate-900/40"
                      >
                        <td className="truncate px-3 py-4 text-sm font-medium tabular-nums text-slate-700 dark:text-slate-200">
                          <Link
                            href={transactionDetailHref(tx.trx_id)}
                            prefetch={false}
                            className="hover:text-brand-700 dark:hover:text-brand-300"
                          >
                            {tx.trx_id}
                          </Link>
                        </td>
                        <td className="truncate px-3 py-4 text-sm font-medium text-slate-700 dark:text-slate-200">
                          <Link
                            href={transactionDetailHref(tx.trx_id)}
                            prefetch={false}
                            className="hover:text-brand-700 dark:hover:text-brand-300"
                          >
                            {buildName(rd)}
                          </Link>
                        </td>
                        <td className="truncate px-3 py-4 text-sm font-medium text-slate-700 dark:text-slate-200">
                          {rd.type}
                        </td>
                        <td className="px-3 py-4 text-start text-sm font-medium tabular-nums text-slate-700 dark:text-slate-200">
                          {rd.send_money} {rd.sender_currency}
                        </td>
                        <td className="px-3 py-4 text-start text-sm font-medium tabular-nums text-slate-700 dark:text-slate-200">
                          {receiverAmount} {rd.receiver_currency}
                        </td>
                        <td className="px-3 py-4">
                          <StatusBadge status={mapTransactionStatus(tx.status)} />
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}

          {pageCount > 1 && (
            <div className="mt-5 border-t border-slate-100 pt-5 dark:border-slate-800/80">
              <Pagination page={safePage} pageCount={pageCount} onPageChange={setPage} />
            </div>
          )}
        </CardContent>
      </Card>

      {successRedirect && (
        <TransferSuccessModal
          open
          onClose={dismissSuccessRedirect}
          trxId={successRedirect.trxId}
          shareLink={successRedirect.shareLink}
          downloadLink={successRedirect.downloadLink}
        />
      )}
    </Container>
  );
}
