// Period Store - Zustand store for fiscal period management

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type {
  FiscalYear,
  AccountingPeriod,
  VATPeriod,
  PeriodContext,
  PeriodSettings,
} from '@/types/periods';

interface PeriodState {
  // Fiscal years
  fiscalYears: FiscalYear[];
  currentFiscalYear: FiscalYear | null;
  selectedFiscalYear: FiscalYear | null; // User-selected fiscal year (persisted)

  // Accounting periods
  periods: AccountingPeriod[];
  currentPeriod: AccountingPeriod | null;
  selectedPeriod: AccountingPeriod | null;

  // VAT periods
  vatPeriods: VATPeriod[];
  selectedVATPeriod: VATPeriod | null;

  // Comparison
  comparisonPeriod: AccountingPeriod | null;
  comparisonType: 'previous-period' | 'previous-year' | 'custom' | null;

  // Settings
  periodSettings: PeriodSettings | null;

  // Loading states
  isLoading: boolean;

  // Actions - Fiscal Years
  setFiscalYears: (years: FiscalYear[]) => void;
  setCurrentFiscalYear: (year: FiscalYear | null) => void;
  setSelectedFiscalYear: (year: FiscalYear | null) => void;
  selectFiscalYear: (yearId: string) => void;
  addFiscalYear: (year: FiscalYear) => void;
  updateFiscalYear: (id: string, updates: Partial<FiscalYear>) => void;
  closeFiscalYear: (id: string, closedBy: string) => void;
  reopenFiscalYear: (id: string, reopenedBy: string) => void;
  lockFiscalYear: (id: string, lockedBy: string) => void;

  // Actions - Accounting Periods
  setPeriods: (periods: AccountingPeriod[]) => void;
  setCurrentPeriod: (period: AccountingPeriod | null) => void;
  setSelectedPeriod: (period: AccountingPeriod | null) => void;
  updatePeriod: (id: string, updates: Partial<AccountingPeriod>) => void;
  closePeriod: (id: string, closedBy: string) => void;
  reopenPeriod: (id: string, reopenedBy: string) => void;
  lockPeriod: (id: string, lockedBy: string) => void;

  // Actions - VAT Periods
  setVATPeriods: (periods: VATPeriod[]) => void;
  setSelectedVATPeriod: (period: VATPeriod | null) => void;
  updateVATPeriod: (id: string, updates: Partial<VATPeriod>) => void;

  // Actions - Comparison
  setComparisonPeriod: (period: AccountingPeriod | null, type: PeriodState['comparisonType']) => void;
  clearComparison: () => void;

  // Actions - Settings
  setPeriodSettings: (settings: PeriodSettings) => void;

  // Actions - Loading
  setLoading: (loading: boolean) => void;

  // Computed/derived
  getContext: () => PeriodContext;
  getPeriodById: (id: string) => AccountingPeriod | undefined;
  getVATPeriodById: (id: string) => VATPeriod | undefined;
  getFiscalYearById: (id: string) => FiscalYear | undefined;
  getFiscalYearForDate: (date: string) => FiscalYear | undefined;
  getPeriodsForYear: (fiscalYearId: string) => AccountingPeriod[];
  getOpenPeriods: () => AccountingPeriod[];
  getOpenFiscalYears: () => FiscalYear[];
  getEffectiveFiscalYear: () => FiscalYear | null;
  canPostToDate: (date: string) => { allowed: boolean; reason?: string; reasonDanish?: string };

  // Reset
  resetPeriodState: () => void;
}

const initialState = {
  fiscalYears: [],
  currentFiscalYear: null,
  selectedFiscalYear: null,
  periods: [],
  currentPeriod: null,
  selectedPeriod: null,
  vatPeriods: [],
  selectedVATPeriod: null,
  comparisonPeriod: null,
  comparisonType: null as PeriodState['comparisonType'],
  periodSettings: null,
  isLoading: false,
};

export const usePeriodStore = create<PeriodState>()(
  persist(
    (set, get) => ({
      ...initialState,

      // Fiscal Years Actions
      setFiscalYears: (years) => set({ fiscalYears: years }),

      setCurrentFiscalYear: (year) => set({ currentFiscalYear: year }),

      addFiscalYear: (year) =>
        set((state) => ({
          fiscalYears: [...state.fiscalYears, year],
        })),

      setSelectedFiscalYear: (year) => set({ selectedFiscalYear: year }),

      selectFiscalYear: (yearId) => {
        const year = get().fiscalYears.find((y) => y.id === yearId);
        if (year) {
          set({ selectedFiscalYear: year, currentFiscalYear: year });
        }
      },

      updateFiscalYear: (id, updates) =>
        set((state) => ({
          fiscalYears: state.fiscalYears.map((y) =>
            y.id === id ? { ...y, ...updates } : y
          ),
          currentFiscalYear:
            state.currentFiscalYear?.id === id
              ? { ...state.currentFiscalYear, ...updates }
              : state.currentFiscalYear,
          selectedFiscalYear:
            state.selectedFiscalYear?.id === id
              ? { ...state.selectedFiscalYear, ...updates }
              : state.selectedFiscalYear,
        })),

      closeFiscalYear: (id, closedBy) => {
        const now = new Date().toISOString();
        get().updateFiscalYear(id, {
          status: 'closed',
          closingDate: now,
          closedBy,
        });
      },

      reopenFiscalYear: (id, _reopenedBy) => {
        get().updateFiscalYear(id, {
          status: 'open',
          closingDate: undefined,
          closedBy: undefined,
        });
      },

      lockFiscalYear: (id, lockedBy) => {
        const now = new Date().toISOString();
        get().updateFiscalYear(id, {
          status: 'locked',
          closingDate: now,
          closedBy: lockedBy,
        });
      },

      // Accounting Periods Actions
      setPeriods: (periods) => set({ periods }),

      setCurrentPeriod: (period) => set({ currentPeriod: period }),

      setSelectedPeriod: (period) => set({ selectedPeriod: period }),

      updatePeriod: (id, updates) =>
        set((state) => ({
          periods: state.periods.map((p) =>
            p.id === id ? { ...p, ...updates } : p
          ),
          currentPeriod:
            state.currentPeriod?.id === id
              ? { ...state.currentPeriod, ...updates }
              : state.currentPeriod,
          selectedPeriod:
            state.selectedPeriod?.id === id
              ? { ...state.selectedPeriod, ...updates }
              : state.selectedPeriod,
        })),

      closePeriod: (id, closedBy) => {
        const now = new Date().toISOString();
        get().updatePeriod(id, {
          status: 'closed',
          closedAt: now,
          closedBy,
        });
      },

      reopenPeriod: (id, reopenedBy) => {
        const now = new Date().toISOString();
        get().updatePeriod(id, {
          status: 'open',
          reopenedAt: now,
          reopenedBy,
          closedAt: undefined,
          closedBy: undefined,
        });
      },

      lockPeriod: (id, lockedBy) => {
        const now = new Date().toISOString();
        get().updatePeriod(id, {
          status: 'locked',
          lockedAt: now,
          lockedBy,
        });
      },

      // VAT Periods Actions
      setVATPeriods: (periods) => set({ vatPeriods: periods }),

      setSelectedVATPeriod: (period) => set({ selectedVATPeriod: period }),

      updateVATPeriod: (id, updates) =>
        set((state) => ({
          vatPeriods: state.vatPeriods.map((p) =>
            p.id === id ? { ...p, ...updates } : p
          ),
          selectedVATPeriod:
            state.selectedVATPeriod?.id === id
              ? { ...state.selectedVATPeriod, ...updates }
              : state.selectedVATPeriod,
        })),

      // Comparison Actions
      setComparisonPeriod: (period, type) =>
        set({
          comparisonPeriod: period,
          comparisonType: type,
        }),

      clearComparison: () =>
        set({
          comparisonPeriod: null,
          comparisonType: null,
        }),

      // Settings Actions
      setPeriodSettings: (settings) => set({ periodSettings: settings }),

      // Loading Actions
      setLoading: (isLoading) => set({ isLoading }),

      // Computed/Derived
      getContext: () => {
        const state = get();
        return {
          currentFiscalYear: state.currentFiscalYear,
          currentPeriod: state.currentPeriod,
          selectedPeriod: state.selectedPeriod,
          selectedVATPeriod: state.selectedVATPeriod,
          comparisonPeriod: state.comparisonPeriod,
          comparisonType: state.comparisonType,
        };
      },

      getPeriodById: (id) => get().periods.find((p) => p.id === id),

      getVATPeriodById: (id) => get().vatPeriods.find((p) => p.id === id),

      getFiscalYearById: (id) => get().fiscalYears.find((y) => y.id === id),

      getFiscalYearForDate: (date) => {
        const targetDate = new Date(date);
        return get().fiscalYears.find((y) => {
          const start = new Date(y.startDate);
          const end = new Date(y.endDate);
          return targetDate >= start && targetDate <= end;
        });
      },

      getPeriodsForYear: (fiscalYearId) =>
        get().periods.filter((p) => p.fiscalYearId === fiscalYearId),

      getOpenPeriods: () =>
        get().periods.filter((p) => p.status === 'open'),

      getOpenFiscalYears: () =>
        get().fiscalYears.filter((y) => y.status === 'open'),

      getEffectiveFiscalYear: () => {
        const state = get();
        return state.selectedFiscalYear || state.currentFiscalYear;
      },

      canPostToDate: (date) => {
        const state = get();
        const dateParts = date.split('-');
        const targetDate = new Date(
          parseInt(dateParts[0]),
          parseInt(dateParts[1]) - 1,
          parseInt(dateParts[2])
        );

        // Find the period for this date
        const period = state.periods.find((p) => {
          const start = new Date(p.startDate);
          const end = new Date(p.endDate);
          return targetDate >= start && targetDate <= end;
        });

        if (!period) {
          return {
            allowed: false,
            reason: 'No period found for this date',
            reasonDanish: 'Ingen periode fundet for denne dato',
          };
        }

        if (period.status === 'locked') {
          return {
            allowed: false,
            reason: 'Period is locked',
            reasonDanish: 'Perioden er laast',
          };
        }

        if (
          period.status === 'closed' &&
          state.periodSettings?.preventPostingToClosedPeriods
        ) {
          return {
            allowed: false,
            reason: 'Period is closed',
            reasonDanish: 'Perioden er lukket',
          };
        }

        if (
          period.status === 'future' &&
          state.periodSettings?.preventPostingToFuturePeriods
        ) {
          return {
            allowed: false,
            reason: 'Cannot post to future periods',
            reasonDanish: 'Kan ikke bogfoere i fremtidige perioder',
          };
        }

        return { allowed: true };
      },

      // Reset
      resetPeriodState: () => set(initialState),
    }),
    {
      name: 'books-period-storage',
      partialize: (state) => ({
        selectedFiscalYear: state.selectedFiscalYear,
        selectedPeriod: state.selectedPeriod,
        selectedVATPeriod: state.selectedVATPeriod,
        comparisonType: state.comparisonType,
      }),
    }
  )
);

// =====================================================
// SELECTOR HOOKS
// =====================================================

export const useCurrentFiscalYear = () =>
  usePeriodStore((state) => state.currentFiscalYear);

export const useSelectedFiscalYear = () =>
  usePeriodStore((state) => state.selectedFiscalYear);

export const useEffectiveFiscalYear = () =>
  usePeriodStore((state) => state.getEffectiveFiscalYear());

export const useFiscalYears = () =>
  usePeriodStore((state) => state.fiscalYears);

export const useOpenFiscalYears = () =>
  usePeriodStore((state) => state.getOpenFiscalYears());

export const useCurrentPeriod = () =>
  usePeriodStore((state) => state.currentPeriod);

export const useSelectedPeriod = () =>
  usePeriodStore((state) => state.selectedPeriod);

export const useSelectedVATPeriod = () =>
  usePeriodStore((state) => state.selectedVATPeriod);

export const usePeriodContext = () =>
  usePeriodStore((state) => state.getContext());

export const useOpenPeriods = () =>
  usePeriodStore((state) => state.getOpenPeriods());

export const usePeriodSettings = () =>
  usePeriodStore((state) => state.periodSettings);

export const useCanPostToDate = (date: string) =>
  usePeriodStore((state) => state.canPostToDate(date));
