"use client";

import { useCallback, useEffect, useState } from "react";

import { getWalletLogs } from "@/api/wallet";
import { usePlayerSessionStore } from "@/stores/player-session-store";
import type { WalletPendingTransfer } from "@/types/api/wallet-logs";

export const WALLET_LOGS_REFRESH_EVENT = "lottery:wallet-logs-refreshed";
const WALLET_NOTIFICATION_READ_KEY = "lottery:wallet-notification-read-transfer-nos";
let pendingReconcileInFlight: Promise<WalletPendingTransfer[]> | null = null;
let pendingReconcileCache: WalletPendingTransfer[] | null = null;
let pendingReconcileFetchedAtMs = 0;
const PENDING_RECONCILE_CACHE_TTL_MS = 5_000;

async function fetchPendingWalletReconcile(): Promise<WalletPendingTransfer[]> {
  const now = Date.now();
  if (
    pendingReconcileCache !== null &&
    now - pendingReconcileFetchedAtMs < PENDING_RECONCILE_CACHE_TTL_MS
  ) {
    return pendingReconcileCache;
  }

  if (pendingReconcileInFlight) {
    return pendingReconcileInFlight;
  }

  pendingReconcileInFlight = getWalletLogs({ page: 1, size: 1 })
    .then((data) => {
      pendingReconcileCache = data.pending_reconcile ?? [];
      pendingReconcileFetchedAtMs = Date.now();
      return pendingReconcileCache;
    })
    .catch(() => [])
    .finally(() => {
      pendingReconcileInFlight = null;
    });

  return pendingReconcileInFlight;
}

type WalletLogsRefreshDetail = {
  pending?: WalletPendingTransfer[];
};

export function usePendingWalletReconcile(): {
  pending: WalletPendingTransfer[];
  unreadPending: WalletPendingTransfer[];
  unreadCount: number;
  hasPending: boolean;
  hasUnread: boolean;
  loading: boolean;
  refresh: () => Promise<void>;
  markAsRead: (transferNo: string) => void;
  markAllAsRead: () => void;
} {
  const bearerToken = usePlayerSessionStore((s) => s.bearerToken);
  const [pending, setPending] = useState<WalletPendingTransfer[]>([]);
  const [readTransferNos, setReadTransferNos] = useState<Set<string>>(() => {
    if (typeof window === "undefined") return new Set();
    try {
      const raw = window.localStorage.getItem(WALLET_NOTIFICATION_READ_KEY);
      if (!raw) return new Set();
      const parsed = JSON.parse(raw);
      if (!Array.isArray(parsed)) return new Set();
      return new Set(
        parsed.filter((value): value is string => typeof value === "string" && value.trim() !== ""),
      );
    } catch {
      return new Set();
    }
  });
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (typeof window === "undefined") return;
    try {
      window.localStorage.setItem(WALLET_NOTIFICATION_READ_KEY, JSON.stringify(Array.from(readTransferNos)));
    } catch {
      // ignore storage quota or privacy mode errors
    }
  }, [readTransferNos]);

  const refresh = useCallback(async (): Promise<void> => {
    if (!bearerToken?.trim()) {
      setPending([]);
      pendingReconcileCache = null;
      pendingReconcileFetchedAtMs = 0;
      return;
    }
    setLoading(true);
    try {
      const nextPending = await fetchPendingWalletReconcile();
      setPending(nextPending);
    } finally {
      setLoading(false);
    }
  }, [bearerToken]);

  useEffect(() => {
    queueMicrotask(() => {
      void refresh();
    });

    function onWalletLogsRefreshed(event: Event): void {
      const detail = (event as CustomEvent<WalletLogsRefreshDetail>).detail;
      if (Array.isArray(detail?.pending)) {
        setPending(detail.pending);
        return;
      }
      void refresh();
    }

    window.addEventListener(WALLET_LOGS_REFRESH_EVENT, onWalletLogsRefreshed);
    return () => window.removeEventListener(WALLET_LOGS_REFRESH_EVENT, onWalletLogsRefreshed);
  }, [refresh]);

  const markAsRead = useCallback((transferNo: string): void => {
    const normalized = transferNo.trim();
    if (!normalized) return;
    setReadTransferNos((prev) => {
      if (prev.has(normalized)) return prev;
      const next = new Set(prev);
      next.add(normalized);
      return next;
    });
  }, []);

  const markAllAsRead = useCallback((): void => {
    if (pending.length === 0) return;
    setReadTransferNos(new Set(pending.map((item) => item.transfer_no)));
  }, [pending]);

  const unreadPending = pending.filter((item) => !readTransferNos.has(item.transfer_no));

  return {
    pending,
    unreadPending,
    unreadCount: unreadPending.length,
    hasPending: pending.length > 0,
    hasUnread: unreadPending.length > 0,
    loading,
    refresh,
    markAsRead,
    markAllAsRead,
  };
}

export function dispatchWalletLogsRefresh(pending: WalletPendingTransfer[]): void {
  if (typeof window === "undefined") return;
  window.dispatchEvent(
    new CustomEvent<WalletLogsRefreshDetail>(WALLET_LOGS_REFRESH_EVENT, {
      detail: { pending },
    }),
  );
}
