'use client';

import {useCallback, useEffect, useRef, useState} from 'react';

type Resource<T> = {key: string | null; data: T | null; error: string; loading: boolean};

/** Refresh a private ticket resource without discarding the last successful view. */
export function useTicketResource<T>(url: string | null) {
  const [state, setState] = useState<Resource<T>>({key: url, data: null, error: '', loading: !!url});
  const key = useRef(url);
  const generation = useRef(0);
  const controller = useRef<AbortController | null>(null);
  const mounted = useRef(false);
  const cancelRequests = useCallback(() => {
    mounted.current = false;
    ++generation.current;
    controller.current?.abort();
    controller.current = null;
  }, []);

  const reload = useCallback(async (quiet = false) => {
    if (!url || key.current !== url || !mounted.current || (quiet && controller.current)) return;
    controller.current?.abort();
    const current = new AbortController(), revision = ++generation.current;
    controller.current = current;
    setState(previous => ({key: url, data: previous.key === url ? previous.data : null, error: '', loading: true}));
    const active = () => mounted.current && key.current === url && generation.current === revision && !current.signal.aborted;
    try {
      const response = await fetch(url, {cache: 'no-store', credentials: 'same-origin', signal: current.signal});
      const body = await response.json();
      if (!active()) return;
      if (!response.ok) {
        if (response.status === 401) window.dispatchEvent(new Event('planck:session-refresh'));
        const message = body && typeof body === 'object' && 'error' in body && typeof body.error === 'string' ? body.error : 'دریافت تیکت‌ها انجام نشد. دوباره تلاش کنید.';
        throw new Error(message);
      }
      setState({key: url, data: body as T, error: '', loading: false});
    } catch (error) {
      if (!active()) return;
      setState(previous => ({...previous, loading: false, error: quiet && previous.data ? '' : error instanceof Error && !(error instanceof TypeError) && !(error instanceof SyntaxError) ? error.message : 'ارتباط برقرار نشد. دوباره تلاش کنید.'}));
    } finally {
      if (generation.current === revision) controller.current = null;
    }
  }, [url]);

  const replace = useCallback((data: T | ((current: T | null) => T)) => {
    if (!mounted.current || key.current !== url) return;
    ++generation.current;
    controller.current?.abort();
    controller.current = null;
    setState(previous => ({key: url, data: typeof data === 'function' ? (data as (current: T | null) => T)(previous.key === url ? previous.data : null) : data, error: '', loading: false}));
  }, [url]);

  useEffect(() => {
    key.current = url;
    mounted.current = true;
    let disposed = false;
    queueMicrotask(() => {if (!disposed && url) void reload();});
    const visible = () => {if (document.visibilityState === 'visible') void reload(true);};
    const timer = url ? window.setInterval(visible, 30000) : undefined;
    if (url) {
      document.addEventListener('visibilitychange', visible);
      window.addEventListener('focus', visible);
    }
    return () => {
      disposed = true;
      cancelRequests();
      if (timer !== undefined) window.clearInterval(timer);
      document.removeEventListener('visibilitychange', visible);
      window.removeEventListener('focus', visible);
    };
  }, [url, reload, cancelRequests]);

  return {...(state.key === url ? state : {key: url, data: null, error: '', loading: !!url}), reload, replace};
}
