"use client";

import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { CalendarRange, ChevronDown, ChevronRight, Search, SlidersHorizontal } from "lucide-react";
import { useTranslation } from "react-i18next";

import { getDrawCurrent } from "@/api/draw";
import { getTicketItems } from "@/api/ticket-items";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Input } from "@/components/ui/input";
import { PlayerPanel } from "@/components/layout/player-panel";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Skeleton } from "@/components/ui/skeleton";
import { groupTicketItems, ticketDetailHref } from "@/features/orders/group-ticket-items";
import { OrderMetaLine } from "@/features/orders/order-meta-line";
import { StatusDot, ticketStatusDisplay } from "@/features/orders/ticket-item-status";
import { useCurrencyCatalog } from "@/hooks/use-currency-catalog";

import { LOTTERY_SCHEDULE_TIMEZONE } from "@/lib/lottery-schedule-timezone";
import { formatMinorAsCurrency } from "@/lib/money";
import { isCreditFundingPlayer } from "@/lib/player-funding-mode";
import {
  formatSchedulePickerYmd,
  getTimeZoneShortLabel,
  parseSchedulePickerYmd,
  scheduleTodayYmd,
} from "@/lib/player-datetime";
import { useActivePlayerCurrency } from "@/hooks/use-active-player-currency";
import { usePlayerSessionStore } from "@/stores/player-session-store";
import { playLabel } from "@/lib/play-labels";
import { cn } from "@/lib/utils";
import type { TicketItemListRow } from "@/types/api/ticket-items";

const ORDERS_PAGE_SIZE = 20;
const STATUS_OPTIONS = [
  "pending_confirm",
  "partial_pending_confirm",
  "pending_draw",
  "partial_failed",
  "pending_payout",
  "settled_win",
  "settled_lose",
  "failed",
  "refunded",
] as const;

export function TicketOrdersListScreen() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const { t } = useTranslation("player");
  const { activeCurrency } = useActivePlayerCurrency();
  const creditMode = isCreditFundingPlayer(usePlayerSessionStore((state) => state.profile));
  useCurrencyCatalog();
  const drawNoFilter = useMemo(() => (searchParams.get("draw_no") ?? "").trim(), [searchParams]);
  const numberFilter = useMemo(() => (searchParams.get("number") ?? "").trim(), [searchParams]);
  const statusFilter = useMemo(
    () => searchParams.getAll("status").map((s) => s.trim()).filter(Boolean),
    [searchParams],
  );
  const hasUrlFilters = drawNoFilter !== "" || numberFilter !== "" || statusFilter.length > 0;

  const [items, setItems] = useState<TicketItemListRow[]>([]);
  const [page, setPage] = useState(1);
  const [lastPage, setLastPage] = useState(1);
  const [total, setTotal] = useState(0);
  const [loading, setLoading] = useState(true);
  const [loadingMore, setLoadingMore] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [queryDrawNoState, setQueryDrawNoState] = useState(() => ({
    base: drawNoFilter,
    draft: drawNoFilter,
  }));
  const [queryNumberDraft, setQueryNumberDraft] = useState("");
  const queryNumber = numberFilter || queryNumberDraft;
  const [filtersOpen, setFiltersOpen] = useState(hasUrlFilters);
  const [filtersCollapsed, setFiltersCollapsed] = useState(false);
  const filtersExpanded = hasUrlFilters ? !filtersCollapsed : filtersOpen;
  const [queryStatuses, setQueryStatuses] = useState<string[]>(statusFilter);
  const [fromDate, setFromDate] = useState("");
  const [toDate, setToDate] = useState("");
  const [rangeOpen, setRangeOpen] = useState(false);
  const [statusOpen, setStatusOpen] = useState(false);
  const [calendarMonth, setCalendarMonth] = useState(() => new Date());
  const [scheduleTimezone, setScheduleTimezone] = useState(LOTTERY_SCHEDULE_TIMEZONE);
  const loadMoreRef = useRef<HTMLDivElement | null>(null);
  const initialLoadDone = useRef(false);

  const queryDrawNoInput =
    queryDrawNoState.base === drawNoFilter ? queryDrawNoState.draft : drawNoFilter;
  const queryDrawNo = queryDrawNoInput || drawNoFilter;

  const selectedRange = useMemo(() => {
    const from = parseSchedulePickerYmd(fromDate);
    const to = parseSchedulePickerYmd(toDate);
    if (!from && !to) return undefined;
    if (from && to) return { from, to };
    if (from) return { from };
    return to ? { from: to } : undefined;
  }, [fromDate, toDate]);

  const formatCompactDate = useCallback((value: string) => {
    const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
    if (!m) return value;
    return `${m[2]}-${m[3]}`;
  }, []);

  const dateLabel = useMemo(() => {
    if (!fromDate && !toDate) return t("orders.dateRange");
    if (fromDate && toDate) return `${formatCompactDate(fromDate)} ~ ${formatCompactDate(toDate)}`;
    return `${fromDate ? formatCompactDate(fromDate) : "..." } ~ ${toDate ? formatCompactDate(toDate) : "..."}`;
  }, [formatCompactDate, fromDate, t, toDate]);
  const orderGroups = useMemo(() => groupTicketItems(items), [items]);

  const fetchPage = useCallback(
    async (nextPage: number, append: boolean) => {
      if (append) setLoadingMore(true);
      else setLoading(true);
      setError(null);
      try {
        const res = await getTicketItems({
          page: nextPage,
          per_page: ORDERS_PAGE_SIZE,
          draw_no: queryDrawNo || undefined,
          number: queryNumber || undefined,
          status: queryStatuses.length ? queryStatuses : undefined,
          start_date: fromDate || undefined,
          end_date: toDate || undefined,
        });
        setItems((prev) => (append ? [...prev, ...res.items] : res.items));
        setPage(res.page);
        setLastPage(res.last_page);
        setTotal(res.total);
      } catch {
        setError(t("orders.loadFailed"));
        if (!append) setItems([]);
      } finally {
        setLoading(false);
        setLoadingMore(false);
      }
    },
    [fromDate, queryDrawNo, queryNumber, queryStatuses, t, toDate],
  );

  useEffect(() => {
    void getDrawCurrent()
      .then((res) => {
        const tz = res.data?.schedule_timezone?.trim();
        if (tz) setScheduleTimezone(tz);
      })
      .catch(() => {
        /* 保留默认排期时区 */
      });
  }, []);

  const scheduleTzLabel = useMemo(
    () => getTimeZoneShortLabel(scheduleTimezone),
    [scheduleTimezone],
  );

  useEffect(() => {
    if (!initialLoadDone.current) {
      initialLoadDone.current = true;
      void fetchPage(1, false);
      return;
    }
    setItems([]);
    setPage(1);
    setLastPage(1);
    void fetchPage(1, false);
  }, [fetchPage, queryDrawNo, queryNumber, queryStatuses, fromDate, toDate]);

  useEffect(() => {
    const refreshFromEvents = () => {
      void fetchPage(1, false);
    };
    window.addEventListener("lottery-hall-refresh", refreshFromEvents);
    window.addEventListener("lottery-wallet-refresh", refreshFromEvents);
    return () => {
      window.removeEventListener("lottery-hall-refresh", refreshFromEvents);
      window.removeEventListener("lottery-wallet-refresh", refreshFromEvents);
    };
  }, [fetchPage]);

  useEffect(() => {
    const target = loadMoreRef.current;
    if (!target || loading || loadingMore || page >= lastPage) return;

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry?.isIntersecting) {
          void fetchPage(page + 1, true);
        }
      },
      { rootMargin: "160px" },
    );

    observer.observe(target);
    return () => observer.disconnect();
  }, [fetchPage, lastPage, loading, loadingMore, page]);

  return (
    <PlayerPanel title={t("orders.title")}>
      <div className="space-y-3">
        <div className="rounded-2xl border border-[#dfe9f8] bg-white p-3 shadow-[0_10px_28px_rgba(15,23,42,0.05)]">
          <div className="flex items-center justify-between gap-3">
            <div className="min-w-0 flex-1">
              <p className="text-[11px] font-black uppercase tracking-wide text-[#6f86ad]">
                {drawNoFilter ? t("orders.filteredIssue") : t("orders.totalRecords")}
              </p>
              <p className="mt-0.5 truncate font-mono text-2xl font-black leading-none text-[#0b3f96]">
                {drawNoFilter || total}
              </p>
            </div>
            <div className="flex shrink-0 items-center gap-2">
              <Button
                type="button"
                variant="outline"
                className={cn(
                  "h-9 rounded-full border-[#dce7f7] bg-white px-3 text-xs font-bold text-[#32518d] hover:bg-[#f8fbff]",
                  filtersExpanded && "border-[#b9ccf6] bg-[#f1f6ff] text-[#0b56b7]",
                )}
                onClick={() => {
                  if (hasUrlFilters) {
                    setFiltersCollapsed((value) => !value);
                    return;
                  }
                  setFiltersOpen((value) => !value);
                }}
              >
                <SlidersHorizontal className="size-3.5" />
                {filtersExpanded ? t("orders.hideFilters") : t("orders.showFilters")}
              </Button>
              <Link
                href="/hall"
                className="inline-flex h-9 shrink-0 items-center rounded-full bg-[#e5002c] px-5 text-sm font-black text-white shadow-[0_8px_18px_rgba(229,0,44,0.22)]"
              >
                {t("orders.betNow")}
              </Link>
              {(queryDrawNoInput || queryNumber || fromDate || toDate || queryStatuses.length > 0) ? (
                <Button
                  type="button"
                  variant="outline"
                  className="h-9 rounded-full border-[#dce7f7] bg-white px-3 text-xs font-bold text-[#32518d] hover:bg-[#f8fbff]"
                  onClick={() => {
                    setQueryDrawNoState({ base: "", draft: "" });
                    setQueryNumberDraft("");
                    setFromDate("");
                    setToDate("");
                    setQueryStatuses([]);
                    setFiltersOpen(false);
                    setFiltersCollapsed(false);
                    setRangeOpen(false);
                    setStatusOpen(false);
                    if (hasUrlFilters) {
                      router.replace("/orders");
                    }
                  }}
                >
                  {t("actions.clear")}
                </Button>
              ) : null}
            </div>
          </div>

          {filtersExpanded ? (
          <div className="mt-3 grid grid-cols-2 gap-2">
            <div className="flex h-9 min-w-0 items-center rounded-full border border-[#dce7f7] bg-[#fbfdff] px-3">
                <Input
                  value={queryDrawNoInput}
                  onChange={(e) =>
                    setQueryDrawNoState({ base: drawNoFilter, draft: e.target.value })
                  }
                  placeholder={t("orders.drawNo")}
                  aria-label={t("orders.drawNo")}
                  className="h-8 border-0 bg-transparent px-0 text-base shadow-none focus-visible:ring-0"
                />
            </div>

            <div className="flex h-9 min-w-0 items-center gap-2 rounded-full border border-[#dce7f7] bg-[#fbfdff] px-3">
                <Search className="size-3.5 shrink-0 text-slate-400" />
                <Input
                  value={queryNumber}
                  onChange={(e) => setQueryNumberDraft(e.target.value)}
                  placeholder={t("orders.number")}
                  aria-label={t("orders.number")}
                  className="h-8 border-0 bg-transparent px-0 text-base shadow-none focus-visible:ring-0"
                />
            </div>

            <Popover open={rangeOpen} onOpenChange={setRangeOpen}>
              <PopoverTrigger
                render={
                  <Button
                    type="button"
                    variant="outline"
                    className="h-9 w-full justify-start gap-2 rounded-full border-[#dce7f7] bg-[#fbfdff] px-3 text-left text-sm font-bold text-[#32518d] hover:bg-white"
                  >
                    <CalendarRange className="size-4 text-[#7890b8]" />
                    <span className="truncate">{dateLabel}</span>
                  </Button>
                }
              />
              <PopoverContent align="start" className="w-auto border-[#dce7f7] p-2 shadow-[0_16px_40px_rgba(15,23,42,0.14)]">
                <p className="mb-2 px-1 text-[11px] leading-snug text-muted-foreground">
                  {t("orders.dateRangeHint", { tz: scheduleTzLabel })}
                </p>
                <Calendar
                  mode="range"
                  month={calendarMonth}
                  onMonthChange={setCalendarMonth}
                  numberOfMonths={1}
                  selected={selectedRange}
                  onSelect={(range) => {
                    if (!range?.from && !range?.to) {
                      setFromDate("");
                      setToDate("");
                      return;
                    }
                    setFromDate(range?.from ? formatSchedulePickerYmd(range.from) : "");
                    setToDate(range?.to ? formatSchedulePickerYmd(range.to) : "");
                  }}
                />
                <div className="flex items-center justify-between gap-2 border-t px-2 py-1.5">
                  <Button
                    type="button"
                    variant="ghost"
                    size="xs"
                    onClick={() => {
                      const today = scheduleTodayYmd(scheduleTimezone);
                      setFromDate(today);
                      setToDate(today);
                    }}
                  >
                    {t("orders.scheduleToday")}
                  </Button>
                  <div className="flex items-center gap-2">
                  <Button
                    type="button"
                    variant="ghost"
                    size="xs"
                    onClick={() => {
                        setFromDate("");
                        setToDate("");
                    }}
                  >
                    {t("actions.clear")}
                  </Button>
                  <Button type="button" variant="secondary" size="xs" onClick={() => setRangeOpen(false)}>
                    {t("actions.done")}
                  </Button>
                  </div>
                </div>
              </PopoverContent>
            </Popover>

            <Popover open={statusOpen} onOpenChange={setStatusOpen}>
              <PopoverTrigger
                render={
                  <Button
                    type="button"
                    variant="outline"
                    className="h-9 w-full justify-between gap-2 rounded-full border-[#dce7f7] bg-[#fbfdff] px-3 text-sm font-bold text-[#32518d] hover:bg-white"
                  >
                    <span className="flex min-w-0 items-center gap-1.5">
                      <span className="shrink-0">{t("orders.status")}</span>
                      {queryStatuses.length ? (
                        <span className="truncate text-[#0b56b7]">
                          {t(`ticketStatus.${queryStatuses[0]}`, { defaultValue: queryStatuses[0] })}
                        </span>
                      ) : null}
                    </span>
                    <span className="flex items-center gap-1 text-[#7890b8]">
                      <ChevronDown className="size-3.5" />
                    </span>
                  </Button>
                }
              />
              <PopoverContent align="start" className="w-56 border-[#dce7f7] p-1.5 shadow-[0_16px_40px_rgba(15,23,42,0.14)]">
                <div className="space-y-0.5">
                  <button
                    type="button"
                    className={cn(
                      "flex w-full items-center rounded-md px-2 py-1.5 text-left text-[13px] font-semibold transition-colors",
                      queryStatuses.length === 0 ? "bg-[#eaf2ff] text-[#0b56b7]" : "text-[#32518d] hover:bg-[#f8fbff]",
                    )}
                    onClick={() => setQueryStatuses([])}
                  >
                    {t("actions.all", { defaultValue: "全部" })}
                  </button>
                  {STATUS_OPTIONS.map((status) => {
                    const checked = queryStatuses[0] === status;
                    return (
                      <button
                        key={status}
                        type="button"
                        className={cn(
                          "flex w-full items-center rounded-md px-2 py-1.5 text-left text-[13px] font-semibold transition-colors",
                          checked ? "bg-[#eaf2ff] text-[#0b56b7]" : "text-[#32518d] hover:bg-[#f8fbff]",
                        )}
                        onClick={() => {
                          setQueryStatuses(checked ? [] : [status]);
                          setStatusOpen(false);
                        }}
                      >
                        <span className="truncate">{t(`ticketStatus.${status}`, { defaultValue: status })}</span>
                      </button>
                    );
                  })}
                </div>
              </PopoverContent>
            </Popover>
          </div>
          ) : null}
        </div>

        {loading ? (
          <div className="space-y-3">
            {Array.from({ length: 5 }).map((_, i) => (
              <Skeleton key={i} className="h-28 w-full rounded-xl" />
            ))}
          </div>
        ) : error ? (
          <div className="rounded-xl border border-red-200 bg-red-50 px-3 py-3 text-sm text-red-700">
            <p>{error}</p>
            <Button
              type="button"
              size="sm"
              className="mt-3 bg-[#e5002c] text-white hover:bg-[#d10028]"
              onClick={() => void fetchPage(1, false)}
            >
              {t("actions.retry")}
            </Button>
          </div>
        ) : items.length === 0 ? (
          <div className="rounded-xl border border-dashed border-[#dce7f7] bg-[#f8fbff] px-3 py-8 text-center">
            <p className="text-sm font-bold text-slate-700">{t("orders.empty")}</p>
            <Link
              href="/hall"
              className="mt-4 inline-flex h-9 items-center rounded-lg bg-[#e5002c] px-4 text-sm font-bold text-white"
            >
              {t("orders.submitBet")}
            </Link>
          </div>
        ) : (
          <>
            <div className="space-y-3">
              {orderGroups.map((group) => {
                const cur = group.currency_code ?? activeCurrency;
                const st = ticketStatusDisplay(
                  group.status,
                  group.win_amount,
                  group.jackpot_win_amount,
                  t,
                  creditMode,
                );
                const totalWin = group.win_amount + group.jackpot_win_amount;
                return (
                  <div
                    key={group.key}
                    className="rounded-xl border border-[#e5edf8] bg-white shadow-[0_8px_24px_rgba(15,23,42,0.05)]"
                  >
                    <div className="p-3 pb-2">
                      <div className="flex items-start justify-between gap-3">
                        <p className="min-w-0 truncate font-mono text-sm font-black text-[#0b3f96]">
                          {group.draw_no ?? "—"}
                        </p>
                        <StatusDot label={st.label} dotClass={st.dotClass} ring={st.ring} />
                      </div>
                      <OrderMetaLine
                        orderNo={group.order_no}
                        placedAt={group.placed_at}
                        t={t}
                      />
                      <div className="mt-3 grid grid-cols-2 gap-2">
                        <div className="rounded-lg bg-[#f8fbff] px-3 py-2">
                          <p className="text-[11px] font-bold uppercase text-[#7890b8]">{t("orders.stake")}</p>
                          <p className="mt-1 text-sm font-black text-slate-900">
                            {formatMinorAsCurrency(group.total_bet_amount, cur)}
                          </p>
                        </div>
                        <div className="rounded-lg bg-[#f8fbff] px-3 py-2">
                          <p className="text-[11px] font-bold uppercase text-[#7890b8]">{t("orders.deduction")}</p>
                          <p className="mt-1 text-sm font-black text-[#0b3f96]">
                            {formatMinorAsCurrency(group.actual_deduct_amount, cur)}
                          </p>
                        </div>
                      </div>
                      {group.status === "partial_failed" ? (
                        <p className="mt-2 text-xs font-bold text-amber-700">
                          {t("orders.partialFailedHint")}
                        </p>
                      ) : null}
                      {totalWin > 0 && group.status === "settled_win" ? (
                        <p className="mt-2 text-xs font-bold text-emerald-600">
                          {t("orders.win", { amount: formatMinorAsCurrency(totalWin, cur) })}
                        </p>
                      ) : null}
                    </div>

                    <div className="space-y-2 border-t border-[#edf2f8] px-3 py-3">
                      <p className="text-[11px] font-bold uppercase tracking-wide text-[#7890b8]">
                        {t("orders.betItems")}
                      </p>
                      {group.items.map((row, index) => {
                        const lineSt = ticketStatusDisplay(
                          row.status,
                          row.win_amount,
                          row.jackpot_win_amount,
                          t,
                          creditMode,
                        );
                        const lineCur = row.currency_code ?? cur;
                        return (
                          <Link
                            key={row.ticket_no}
                            href={ticketDetailHref(row.ticket_no)}
                            aria-label={t("orders.viewBetLine")}
                            className="flex items-center gap-3 rounded-xl border border-[#e5edf8] bg-[#fbfdff] px-3 py-2.5 transition-colors hover:border-[#b9ccf6] hover:bg-white"
                          >
                            <span className="flex size-7 shrink-0 items-center justify-center rounded-full bg-[#eaf2ff] text-xs font-black text-[#0b56b7]">
                              {index + 1}
                            </span>
                            <div className="min-w-0 flex-1">
                              <p className="text-sm font-black text-[#0b3f96]">
                                {playLabel(row.play_code, t)} · {row.original_number ?? row.play_code}
                              </p>
                              <p className="mt-0.5 text-xs text-slate-500">
                                {t("orders.deduction")}{" "}
                                <span className="font-bold tabular-nums text-[#0b3f96]">
                                  {formatMinorAsCurrency(row.actual_deduct_amount, lineCur)}
                                </span>
                              </p>
                            </div>
                            <div className="flex shrink-0 flex-col items-end gap-1">
                              <StatusDot
                                label={lineSt.label}
                                dotClass={lineSt.dotClass}
                                ring={lineSt.ring}
                              />
                              <ChevronRight className="size-4 text-[#7890b8]" aria-hidden />
                            </div>
                          </Link>
                        );
                      })}
                    </div>
                  </div>
                );
              })}
            </div>
            <div ref={loadMoreRef} className="min-h-1" />
            {page < lastPage ? (
              <Button
                type="button"
                variant="outline"
                className="h-10 w-full rounded-xl border-[#dce7f7] bg-white text-sm font-bold text-[#32518d] hover:bg-[#f8fbff]"
                disabled={loadingMore}
                onClick={() => void fetchPage(page + 1, true)}
              >
                {loadingMore ? t("actions.loading") : t("actions.loadMore")}
              </Button>
            ) : lastPage > 1 ? (
              <p className="py-2 text-center text-xs text-slate-400">
                {t("orders.noMore")}
              </p>
            ) : null}
          </>
        )}
      </div>
    </PlayerPanel>
  );
}


