// Period Hook - React hook for period context and validation

import { useMemo, useCallback } from 'react';
import { usePeriodStore } from '@/stores/periodStore';
import {
  getPeriodForDate,
  getPreviousPeriod,
  getSamePeriodPreviousYear,
  getYearToDateRange,
  canPostToDate,
  validatePeriodClose,
} from '@/lib/periods';
import type { AccountingPeriod, FiscalYear, PeriodStatus } from '@/types/periods';
import type { Transaction } from '@/types/accounting';

/**
 * Hook for accessing period context in components
 */
export function usePeriodContext() {
  const {
    currentFiscalYear,
    currentPeriod,
    selectedPeriod,
    selectedVATPeriod,
    comparisonPeriod,
    comparisonType,
    periods,
    fiscalYears,
    vatPeriods,
    isLoading,
  } = usePeriodStore();

  const effectivePeriod = selectedPeriod || currentPeriod;

  return {
    // Current context
    currentFiscalYear,
    currentPeriod,
    selectedPeriod,
    effectivePeriod,
    selectedVATPeriod,
    comparisonPeriod,
    comparisonType,

    // Lists
    periods,
    fiscalYears,
    vatPeriods,

    // Loading
    isLoading,
  };
}

/**
 * Hook for period selection and navigation
 */
export function usePeriodSelector() {
  const {
    periods,
    fiscalYears,
    selectedPeriod,
    setSelectedPeriod,
    setComparisonPeriod,
    clearComparison,
  } = usePeriodStore();

  const selectPeriod = useCallback(
    (periodId: string) => {
      const period = periods.find((p) => p.id === periodId);
      if (period) {
        setSelectedPeriod(period);
      }
    },
    [periods, setSelectedPeriod]
  );

  const selectPreviousPeriod = useCallback(() => {
    if (!selectedPeriod) return;
    const previous = getPreviousPeriod(selectedPeriod, periods);
    if (previous) {
      setSelectedPeriod(previous);
    }
  }, [selectedPeriod, periods, setSelectedPeriod]);

  const selectNextPeriod = useCallback(() => {
    if (!selectedPeriod) return;
    const currentIndex = periods.findIndex((p) => p.id === selectedPeriod.id);
    if (currentIndex >= 0 && currentIndex < periods.length - 1) {
      setSelectedPeriod(periods[currentIndex + 1]);
    }
  }, [selectedPeriod, periods, setSelectedPeriod]);

  const enableComparison = useCallback(
    (type: 'previous-period' | 'previous-year' | 'custom', customPeriod?: AccountingPeriod) => {
      if (!selectedPeriod) return;

      let comparisonPeriodData: AccountingPeriod | undefined;

      if (type === 'previous-period') {
        comparisonPeriodData = getPreviousPeriod(selectedPeriod, periods);
      } else if (type === 'previous-year') {
        comparisonPeriodData = getSamePeriodPreviousYear(selectedPeriod, periods);
      } else if (type === 'custom' && customPeriod) {
        comparisonPeriodData = customPeriod;
      }

      if (comparisonPeriodData) {
        setComparisonPeriod(comparisonPeriodData, type);
      }
    },
    [selectedPeriod, periods, setComparisonPeriod]
  );

  const disableComparison = useCallback(() => {
    clearComparison();
  }, [clearComparison]);

  // Get periods grouped by fiscal year
  const periodsByYear = useMemo(() => {
    const grouped: Record<string, AccountingPeriod[]> = {};
    for (const period of periods) {
      if (!grouped[period.fiscalYearId]) {
        grouped[period.fiscalYearId] = [];
      }
      grouped[period.fiscalYearId].push(period);
    }
    return grouped;
  }, [periods]);

  // Get open periods only
  const openPeriods = useMemo(
    () => periods.filter((p) => p.status === 'open'),
    [periods]
  );

  return {
    // State
    selectedPeriod,
    periods,
    fiscalYears,
    periodsByYear,
    openPeriods,

    // Actions
    selectPeriod,
    selectPreviousPeriod,
    selectNextPeriod,
    enableComparison,
    disableComparison,
  };
}

/**
 * Hook for posting validation
 */
export function usePostingValidation() {
  const { periods, periodSettings } = usePeriodStore();

  const validatePostingDate = useCallback(
    (date: string) => {
      if (!periodSettings) {
        // Default to strict validation if no settings
        return canPostToDate(date, periods, {
          preventPostingToClosedPeriods: true,
          preventPostingToFuturePeriods: true,
        });
      }

      return canPostToDate(date, periods, {
        preventPostingToClosedPeriods: periodSettings.preventPostingToClosedPeriods,
        preventPostingToFuturePeriods: periodSettings.preventPostingToFuturePeriods,
      });
    },
    [periods, periodSettings]
  );

  const getPeriodStatus = useCallback(
    (date: string): PeriodStatus | 'no-period' => {
      const period = getPeriodForDate(date, periods);
      return period?.status || 'no-period';
    },
    [periods]
  );

  const isDatePostable = useCallback(
    (date: string): boolean => {
      return validatePostingDate(date).allowed;
    },
    [validatePostingDate]
  );

  return {
    validatePostingDate,
    getPeriodStatus,
    isDatePostable,
  };
}

/**
 * Hook for period management (closing, locking, etc.)
 */
export function usePeriodManagement() {
  const {
    periods,
    closePeriod,
    reopenPeriod,
    lockPeriod,
    updatePeriod,
  } = usePeriodStore();

  const canClosePeriod = useCallback(
    (periodId: string, transactions: Transaction[]): { canClose: boolean; errors: string[]; warnings: string[] } => {
      const period = periods.find((p) => p.id === periodId);
      if (!period) {
        return {
          canClose: false,
          errors: ['Periode ikke fundet'],
          warnings: [],
        };
      }

      const validation = validatePeriodClose(period, transactions, {
        requireAllReconciled: true,
      });

      return {
        canClose: validation.isValid,
        errors: validation.errors.map((e) => e.messageDanish),
        warnings: validation.warnings.map((w) => w.messageDanish),
      };
    },
    [periods]
  );

  const closeAccountingPeriod = useCallback(
    (periodId: string, userId: string) => {
      closePeriod(periodId, userId);
    },
    [closePeriod]
  );

  const reopenAccountingPeriod = useCallback(
    (periodId: string, userId: string) => {
      reopenPeriod(periodId, userId);
    },
    [reopenPeriod]
  );

  const lockAccountingPeriod = useCallback(
    (periodId: string, userId: string) => {
      lockPeriod(periodId, userId);
    },
    [lockPeriod]
  );

  const getPeriodActions = useCallback(
    (periodId: string) => {
      const period = periods.find((p) => p.id === periodId);
      if (!period) return { canClose: false, canReopen: false, canLock: false };

      return {
        canClose: period.status === 'open',
        canReopen: period.status === 'closed',
        canLock: period.status === 'closed',
      };
    },
    [periods]
  );

  return {
    canClosePeriod,
    closeAccountingPeriod,
    reopenAccountingPeriod,
    lockAccountingPeriod,
    getPeriodActions,
  };
}

/**
 * Hook for year-to-date calculations
 */
export function useYearToDate() {
  const { currentFiscalYear, selectedPeriod, periods } = usePeriodStore();

  const ytdRange = useMemo(() => {
    if (!currentFiscalYear || !selectedPeriod) return null;
    return getYearToDateRange(selectedPeriod, currentFiscalYear);
  }, [currentFiscalYear, selectedPeriod]);

  const ytdPeriods = useMemo(() => {
    if (!currentFiscalYear || !selectedPeriod) return [];
    return periods.filter((p) => {
      if (p.fiscalYearId !== currentFiscalYear.id) return false;
      return p.periodNumber <= selectedPeriod.periodNumber;
    });
  }, [currentFiscalYear, selectedPeriod, periods]);

  return {
    ytdRange,
    ytdPeriods,
    fiscalYear: currentFiscalYear,
  };
}

/**
 * Combined hook for common period operations
 */
export function usePeriod() {
  const context = usePeriodContext();
  const selector = usePeriodSelector();
  const validation = usePostingValidation();
  const management = usePeriodManagement();
  const ytd = useYearToDate();

  return {
    // Context
    ...context,

    // Selector
    selectPeriod: selector.selectPeriod,
    selectPreviousPeriod: selector.selectPreviousPeriod,
    selectNextPeriod: selector.selectNextPeriod,
    enableComparison: selector.enableComparison,
    disableComparison: selector.disableComparison,
    periodsByYear: selector.periodsByYear,
    openPeriods: selector.openPeriods,

    // Validation
    validatePostingDate: validation.validatePostingDate,
    getPeriodStatus: validation.getPeriodStatus,
    isDatePostable: validation.isDatePostable,

    // Management
    canClosePeriod: management.canClosePeriod,
    closeAccountingPeriod: management.closeAccountingPeriod,
    reopenAccountingPeriod: management.reopenAccountingPeriod,
    lockAccountingPeriod: management.lockAccountingPeriod,
    getPeriodActions: management.getPeriodActions,

    // YTD
    ytdRange: ytd.ytdRange,
    ytdPeriods: ytd.ytdPeriods,
  };
}
