import { useReducer, useEffect, useRef, useCallback } from "react";
import type { CategoryZoomData } from "../shared/types";
import { getCategoryZoom } from "../services/reportService";
import { useReportsPeriod } from "./useReportsPeriod";

interface State {
  zoomedCategoryId: number | null;
  rollupChildren: boolean;
  data: CategoryZoomData | null;
  isLoading: boolean;
  error: string | null;
}

type Action =
  | { type: "SET_CATEGORY"; payload: number | null }
  | { type: "TOGGLE_ROLLUP"; payload: boolean }
  | { type: "SET_LOADING"; payload: boolean }
  | { type: "SET_DATA"; payload: CategoryZoomData }
  | { type: "SET_ERROR"; payload: string };

const initialState: State = {
  zoomedCategoryId: null,
  rollupChildren: true,
  data: null,
  isLoading: false,
  error: null,
};

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "SET_CATEGORY":
      return { ...state, zoomedCategoryId: action.payload, data: null };
    case "TOGGLE_ROLLUP":
      return { ...state, rollupChildren: action.payload };
    case "SET_LOADING":
      return { ...state, isLoading: action.payload };
    case "SET_DATA":
      return { ...state, data: action.payload, isLoading: false, error: null };
    case "SET_ERROR":
      return { ...state, error: action.payload, isLoading: false };
    default:
      return state;
  }
}

export function useCategoryZoom() {
  const { from, to } = useReportsPeriod();
  const [state, dispatch] = useReducer(reducer, initialState);
  const fetchIdRef = useRef(0);

  const fetch = useCallback(
    async (categoryId: number | null, includeChildren: boolean, dateFrom: string, dateTo: string) => {
      if (categoryId === null) return;
      const id = ++fetchIdRef.current;
      dispatch({ type: "SET_LOADING", payload: true });
      try {
        const data = await getCategoryZoom(categoryId, dateFrom, dateTo, includeChildren);
        if (id !== fetchIdRef.current) return;
        dispatch({ type: "SET_DATA", payload: data });
      } catch (e) {
        if (id !== fetchIdRef.current) return;
        dispatch({ type: "SET_ERROR", payload: e instanceof Error ? e.message : String(e) });
      }
    },
    [],
  );

  useEffect(() => {
    fetch(state.zoomedCategoryId, state.rollupChildren, from, to);
  }, [fetch, state.zoomedCategoryId, state.rollupChildren, from, to]);

  const setCategory = useCallback((id: number | null) => {
    dispatch({ type: "SET_CATEGORY", payload: id });
  }, []);

  const setRollupChildren = useCallback((flag: boolean) => {
    dispatch({ type: "TOGGLE_ROLLUP", payload: flag });
  }, []);

  const refetch = useCallback(() => {
    fetch(state.zoomedCategoryId, state.rollupChildren, from, to);
  }, [fetch, state.zoomedCategoryId, state.rollupChildren, from, to]);

  return { ...state, setCategory, setRollupChildren, refetch, from, to };
}
