import api from '../api';
import { usePlayerProfile } from './usePlayerProfile';
import { usePlayerMessages } from './usePlayerMessages';

interface DepositOrderRow {
  id: string;
  orderNo: string;
  amount: string;
  status: string;
  rejectReason?: string | null;
}

const POLL_FAST_MS = 8_000;
const POLL_SLOW_MS = 30_000;
const TRACKED_STORAGE_KEY = 'player_deposit_tracked_pending';

const lastStatus = new Map<string, string>();
const trackedPending = new Set<string>();
const notifiedKeys = new Set<string>();
let pollTimer: ReturnType<typeof setInterval> | null = null;
let pollingActive = false;

function notifyKey(orderId: string, type: 'approved' | 'rejected') {
  return `${orderId}:${type}`;
}

function loadTrackedFromStorage() {
  try {
    const raw = sessionStorage.getItem(TRACKED_STORAGE_KEY);
    if (!raw) return;
    const ids: string[] = JSON.parse(raw);
    for (const id of ids) {
      if (id) trackedPending.add(String(id));
    }
  } catch {
    /* ignore */
  }
}

function persistTrackedToStorage() {
  try {
    sessionStorage.setItem(TRACKED_STORAGE_KEY, JSON.stringify([...trackedPending]));
  } catch {
    /* ignore */
  }
}

function addTracked(orderId: string) {
  trackedPending.add(orderId);
  persistTrackedToStorage();
}

function removeTracked(orderId: string) {
  if (!trackedPending.delete(orderId)) return;
  persistTrackedToStorage();
}

function hasPendingInterest() {
  return trackedPending.size > 0;
}

function schedulePoll(intervalMs: number) {
  if (pollTimer) clearInterval(pollTimer);
  pollTimer = setInterval(() => {
    void pollOnce();
  }, intervalMs);
}

function adjustPollInterval() {
  if (!pollingActive) return;
  schedulePoll(hasPendingInterest() ? POLL_FAST_MS : POLL_SLOW_MS);
}

function trackPendingOrder(orderId: string) {
  const id = String(orderId);
  if (!id) return;
  addTracked(id);
  lastStatus.set(id, 'PENDING');
  adjustPollInterval();
  void pollOnce();
}

function shouldNotify(orderId: string, prev: string | undefined, next: string) {
  if (next !== 'APPROVED' && next !== 'REJECTED') return false;
  if (prev === 'PENDING') return true;
  if (trackedPending.has(orderId)) return true;
  return false;
}

function handleStatusChange(order: DepositOrderRow): boolean {
  const prev = lastStatus.get(order.id);
  const next = order.status;
  lastStatus.set(order.id, next);

  if (next === 'PENDING') {
    addTracked(order.id);
    return false;
  }

  removeTracked(order.id);

  if (!shouldNotify(order.id, prev, next)) return false;

  const type = next === 'APPROVED' ? 'approved' : 'rejected';
  const key = notifyKey(order.id, type);
  if (notifiedKeys.has(key)) return false;
  notifiedKeys.add(key);

  void usePlayerMessages().refreshUnreadCount();
  return next === 'APPROVED';
}

async function pollOnce() {
  try {
    const { data } = await api.get('/player/deposit-orders', { params: { page: 1 } });
    const items: DepositOrderRow[] = data.data?.items ?? [];
    const { refreshProfile } = usePlayerProfile();

    let needsProfileRefresh = false;
    for (const order of items) {
      if (handleStatusChange(order)) needsProfileRefresh = true;
    }

    if (needsProfileRefresh) await refreshProfile();
    adjustPollInterval();
  } catch {
    /* silent retry on next tick */
  }
}

function onVisibilityChange() {
  if (!document.hidden && pollingActive) void pollOnce();
}

function startPolling() {
  if (pollingActive) {
    void pollOnce();
    return;
  }
  pollingActive = true;
  loadTrackedFromStorage();
  for (const id of trackedPending) {
    if (!lastStatus.has(id)) lastStatus.set(id, 'PENDING');
  }
  document.addEventListener('visibilitychange', onVisibilityChange);
  void pollOnce();
  schedulePoll(hasPendingInterest() ? POLL_FAST_MS : POLL_SLOW_MS);
}

function stopPolling() {
  pollingActive = false;
  trackedPending.clear();
  lastStatus.clear();
  notifiedKeys.clear();
  try {
    sessionStorage.removeItem(TRACKED_STORAGE_KEY);
  } catch {
    /* ignore */
  }
  if (pollTimer) {
    clearInterval(pollTimer);
    pollTimer = null;
  }
  document.removeEventListener('visibilitychange', onVisibilityChange);
}

export function useDepositNotifications() {
  return {
    trackPendingOrder,
    startPolling,
    stopPolling,
    pollOnce,
  };
}
