import { 
  useCallback, 
  useEffect, 
  useRef, 
  useState 
} from 'react';
import { useOutletContext } from 'react-router-dom';
import moment from 'moment';

// components

import BarCharts from '../../common/charting/BarCharts';
import LineCharts from '../../common/charting/LineCharts';

// hooks

import useDebounceLogic from '../useDebounceLogic';
import useLoadingMessages from '../useLoadingMessages';

// functions

import apiLoader from '../../../services/utilities/apiLoader';

// constants

const errorNumber = 367;
const nowRunning = 'hooks/inventory/useSkuHistory.jsx';

function useSkuHistory({ sku, inStock }) {

  const [state, setState] = useState({
    allItems: {}, // All items from the API
    filteredItems: {}, // Filtered items based on `inStock`
    averagesByYear: {}, // Averages by year for all items
    durations: [],
    chartLabel: '',
    average: 0,
    overallAverage: 0,
    tooltipContent: [], // Tooltip content for BarCharts
  });

  const { 
    handleError, 
    level,
    setLoadingMessages 
  } = useOutletContext();
  const { 
    addLoadingMessage, 
    removeLoadingMessage 
  } = useLoadingMessages(setLoadingMessages);

  const previousSkuRef = useRef(null);

  const noAccess = useCallback(() => null, []);

  // Calculate averages by year (independent of inStock filtering).

  const calculateAveragesByYear = useCallback(() => {

    const context = `${nowRunning}.calculateAveragesByYear`;

    try {

      const yearGroups = {};

      Object.values(state.allItems).forEach((item) => {

        const stockedYear = moment(item.stocked).year();
        const stockedDate = moment(item.stocked);
        let endDate;

        if (item.condition < 11) {

          endDate = moment(); // Still in stock.

        } else if (item.condition === 99 && item.orders.length > 0) {

          endDate = moment(
            Math.max(...item.orders.map((order) => new Date(order.orderTime).getTime()))
          ); // Sold.

        } else {

          endDate = moment(item.verified); // Otherwise, verified date.

        }

        const timeInStock = endDate.diff(stockedDate, 'days');

        if (!yearGroups[stockedYear]) {

          yearGroups[stockedYear] = { totalDays: 0, itemCount: 0 };

        }

        yearGroups[stockedYear].totalDays += timeInStock;
        yearGroups[stockedYear].itemCount += 1;

      });

      const averagesByYear = Object.keys(yearGroups).reduce((acc, year) => {

        const { totalDays, itemCount } = yearGroups[year];
        acc[year] = totalDays / itemCount;
        return acc;

      }, {});

      setState((prevState) => ({
        ...prevState,
        averagesByYear,
      }));

    } catch (error) {

      handleError(error, context, errorNumber); 

    }
    
  }, 
  [
    handleError,
    state.allItems
  ]);

  // Filter items based on `inStock` and calculate durations.

  const filterItems = useCallback(() => {

    try {

      const filteredItems = Object.values(state.allItems).filter((item) =>
        inStock ? item.condition < 11 : true
      );
    
      const durations = [];
      let sum = 0;
      let count = 0;
    
      const tooltipContent = filteredItems.map((item) => {

        const days = item.duration || 0;
        const sunkCost = item.sunkCost || 0; // Default to 0 if `sunkCost` is not defined.
        durations.push({ key: `#${item.itemNumber}`, days });
        sum += days;
        count += 1;    
        return `Item ${item.itemNumber}, in stock ${days} day${days !== 1 ? 's' : ''}, Sunk Cost: $${sunkCost.toFixed(2)}`;

      });
    
      const average = count > 0 ? +(sum / count).toFixed(0) : 0;
      const chartLabel = `days in stock (average: ${average})`;
    
      setState((prevState) => ({
        ...prevState,
        filteredItems: filteredItems.reduce((acc, item) => {
          acc[item.itemId] = item;
          return acc;
        }, {}),
        durations,
        average,
        chartLabel,
        tooltipContent,
      }));

    } catch (error) {
        
      handleError(error, `${nowRunning}.filterItems`, errorNumber);

    }
      
  }, 
  [
    handleError,
    inStock, 
    state.allItems
  ]);  

  // Fetch data from the API.

  const runSearch = useCallback(async () => {

    const context = `${nowRunning}.runSearch`;
    const loadingMessage = 'Loading SKU history...';

    try {

      if (!sku || sku.length < 5 || sku === previousSkuRef.current) { return; }

      previousSkuRef.current = sku;

      addLoadingMessage(loadingMessage);

      // Get SKU history data first.

      let api = 'analysis/inventory/sku-history';
      let payload = { sku };
      const { data } = await apiLoader({ api, payload });
      const { 
        failure, 
        items, 
        success 
      } = data;

      if (!success) {

        handleError(failure, context, errorNumber, true);
        return;

      }

      if (Object.keys(items).length === 0) {

        return;

      } else {

        const api = 'analysis/cost_sources/unrecovered-costs';
        const payload = {};
        const { data } = await apiLoader({ api, payload });

        const { 
          failure, 
          success, 
          unrecoveredItems
        } = data;

        if (!success) {

          handleError(failure, context, errorNumber, true);
          return;

        }
  

        Object.entries(unrecoveredItems).forEach(([itemId, details]) => {

          if (items[itemId]) { items[itemId].sunkCost = details.cost; }

        });

        setState((prevState) => ({
          ...prevState,
          allItems: items,
        }));

      }


    } catch (error) {

      handleError(error, context, errorNumber);

    } finally {

      removeLoadingMessage(loadingMessage);

    }

  }, 
  [
    addLoadingMessage, 
    handleError, 
    removeLoadingMessage, 
    sku
  ]);

  const debouncedRunSearch = useDebounceLogic(runSearch, 500);

  // Update charts and filtered items whenever state changes.

  useEffect(() => {
    calculateAveragesByYear();
  }, [state.allItems, calculateAveragesByYear]);

  useEffect(() => {
    filterItems();
  }, [inStock, state.allItems, filterItems]);

  useEffect(() => {
    if (sku && sku.length >= 5) {
      debouncedRunSearch();
    }
  }, [sku, debouncedRunSearch]);

  if (level < 5) {

    return {
      debouncedRunSearch: noAccess,
      filteredItems: {},
      renderItemsChart: noAccess,
      renderLineChart: noAccess
    };
    
  }

  try {

    return {
      
      debouncedRunSearch,
      filteredItems: state.filteredItems,
      renderItemsChart: () => {

        const { 
          chartLabel, 
          durations, 
          tooltipContent 
        } = state;

        if (!durations.length) return null;

        return (

          <BarCharts
            chartLabel={chartLabel}
            dataset={durations}
            errorNumber={errorNumber}
            handleError={handleError}
            key1="days"
            marginLeft={-20} // Adjust the margin to move the bar chart content on mobile devices
            tooltipContent={tooltipContent}
            tooltipFontSize={20}
          />

        );

      },
      renderLineChart: () => {

        const dataset = Object.entries(state.averagesByYear).map(([year, average]) => ({
          year,
          average,
        }));

        if (!dataset.length) return null;

        return (

          <LineCharts
            chartLabel="average shelf life, grouped by year stocked"
            color1="#4dafd8"
            dataset={dataset}
            decimals={0}
            label="year"
            key1="average"
            marginLeft={-20} // Adjust the margin to move the bar chart content on mobile devices
            units=" days"
          />
        );

      }
      
    };

  } catch (error) {
      
    handleError(error, `${nowRunning}.return`, errorNumber);

  }

}

export default useSkuHistory;