'use client';
import { useEffect, useRef, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { api } from '@/lib/api';
import { useAuthStore } from '@/stores/auth';
import { captureCommandGeneration, requireCommandGeneration, requireSelectedStore } from '@/lib/stores/store-context';
import type { StoreCapability, ClockIntent } from '@alqove/api-client';

export function timekeepingError(error: unknown): string {
  if (error && typeof error === 'object') {
    const e = error as { message?: string; error?: { message?: string }; errors?: Record<string, string[]> };
    return [e.error?.message ?? e.message, ...Object.values(e.errors ?? {}).flat()].filter(Boolean).join(' ') || 'Unable to complete the request. Refresh and try again.';
  }
  return 'Unable to complete the request. Refresh and try again.';
}

export function useTimekeepingGuard(store: string, capability?: StoreCapability) {
  const [session] = useState(() => ({ generation: captureCommandGeneration(), user: useAuthStore.getState().user?.id, token: useAuthStore.getState().token }));
  const mounted = useRef(true);
  useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []);
  function assert() {
    requireCommandGeneration(session.generation);
    const state = useAuthStore.getState();
    if (!mounted.current || !state.user || state.isLoading || state.user.id !== session.user || state.token !== session.token || state.selectedStoreId !== store || !state.memberships?.some(m => m.store_id === store)) throw new Error('Store access changed. Refresh and try again.');
    if (capability) requireSelectedStore(store, capability, session.generation);
  }
  return { assert, current: () => { try { assert(); return true; } catch { return false; } } };
}

/** Only explicit validation or known pre-write guards prove no command committed. */
function isDefiniteRejection(error: unknown): boolean {
  if (!error || typeof error !== 'object' || error instanceof Error) return false;
  const e = error as { errors?: Record<string, unknown>; message?: string };
  return !!e.errors || [
    'Stale clock state; refresh before acting.',
    'Wait for the next second before another action.',
    'Period already exported. Download its immutable export instead.',
    'All worked timesheets must be approved before export.',
    'Approved payroll changed. Unlock and approve again.',
  ].includes(e.message ?? '');
}
/** Retains the exact payload/key after uncertainty. A retry is never a new intent. */
export function useStableCommand<T>(execute: (input: T, key: string) => Promise<unknown>, refresh: () => Promise<unknown>, guard?: ReturnType<typeof useTimekeepingGuard>) {
  const pending = useRef<{ input: T; key: string; generation: number } | null>(null);
  const busyRef = useRef(false);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<unknown>(null);
  const [retryable, setRetryable] = useState(false);
  async function run(input?: T) {
    if (busyRef.current || (guard && !guard.current())) return;
    if (input !== undefined) pending.current = { input, key: crypto.randomUUID(), generation: captureCommandGeneration() };
    const command = pending.current;
    if (!command) return;
    busyRef.current = true; setBusy(true); setError(null);
    try {
      guard?.assert();
      requireCommandGeneration(command.generation);
      await execute(command.input, command.key);
      requireCommandGeneration(command.generation);
      if (guard && !guard.current()) return;
      pending.current = null; setRetryable(false);
    } catch (e) {
      if (!guard || guard.current()) {
        setError(e);
        const rejected = isDefiniteRejection(e);
        if (rejected) pending.current = null;
        setRetryable(!rejected);
      }
    } finally {
      if (!guard || guard.current()) {
        await refresh().catch(() => {});
        if (!guard || guard.current()) { busyRef.current = false; setBusy(false); }
      }
    }
  }
  return { run, busy, error, retryable };
}

export function useTimesheets(store: string | null, week: string, own = false) {
  return useQuery({ queryKey: ['timekeeping', store, own ? 'my-hours' : 'timesheets', own ? '' : week], queryFn: () => own ? api.timekeeping.timesheets.own(store!) : api.timekeeping.timesheets.list(store!, week), enabled: !!store && (own || !!week) });
}
export function useTimesheet(store: string, id: string | null) {
  return useQuery({ queryKey: ['timekeeping', store, 'timesheet', id], queryFn: () => api.timekeeping.timesheets.detail(store, id!), enabled: !!id });
}
export function useTimesheetPunches(store: string, member: string | undefined, from: string, to: string, enabled: boolean) {
  return useQuery({ queryKey: ['timekeeping', store, 'punches', member, from, to], queryFn: () => api.timekeeping.punches.list(store, member!, from, to), enabled: enabled && !!member && !!from && !!to });
}
export function useClock(store: string | null) {
  return useQuery({ queryKey: ['timekeeping', store, 'clock'], queryFn: () => api.timekeeping.clock.status(store!), enabled: !!store, refetchInterval: 30_000 });
}
export function useClockCommand(store: string, refresh: () => Promise<unknown>) {
  const guard = useTimekeepingGuard(store);
  return useStableCommand<ClockIntent>((input, key) => api.timekeeping.clock.act(store, input, key), refresh, guard);
}
