/**
 * Recipients Store - Platform-aware recipient management
 * Uses Firebase abstraction layer for cross-platform support
 */
import { create } from 'zustand';
import { doc } from '../firebase';
import { RecipientService, Recipient } from '../services/recipientService';
import { withGlobalLoading } from './uiStore';

export interface RecipientDetailCacheEntry {
  recipient: Recipient | null;
  loading: boolean;
  error: string | null;
  lastFetched?: number;
}

const buildDetailEntry = (
  existing: RecipientDetailCacheEntry | undefined,
  overrides: Partial<RecipientDetailCacheEntry>
): RecipientDetailCacheEntry => ({
  recipient: existing?.recipient ?? null,
  loading: existing?.loading ?? false,
  error: existing?.error ?? null,
  lastFetched: existing?.lastFetched,
  ...overrides,
});

const snapshotExists = (docSnap: any): boolean => {
  const existsValue = docSnap?.exists;
  if (typeof existsValue === 'function') {
    try {
      return !!existsValue.call(docSnap);
    } catch {
      return false;
    }
  }
  return !!existsValue;
};

const normalizeRecipient = (data: Recipient | (Recipient & { createdAt?: any; updatedAt?: any }) | null | undefined): Recipient | null => {
  if (!data) {
    return null;
  }

  const createdAtValue =
    (data.createdAt as any)?.toDate?.() ?? data.createdAt ?? new Date();
  const updatedAtValue =
    (data.updatedAt as any)?.toDate?.() ?? data.updatedAt ?? new Date();

  return {
    ...data,
    createdAt: createdAtValue,
    updatedAt: updatedAtValue,
  };
};

interface RecipientsState {
  // State
  recipients: Recipient[];
  recipientDetails: Record<string, RecipientDetailCacheEntry>;
  loading: boolean;
  error: string | null;
  addError: string | null;
  updateError: string | null;
  deleteError: string | null;
  isInitialized: boolean;
  currentUser: any | null;

  // Actions
  setRecipients: (recipients: Recipient[]) => void;
  setLoading: (loading: boolean) => void;
  setError: (error: string | null) => void;
  setAddError: (error: string | null) => void;
  setUpdateError: (error: string | null) => void;
  setDeleteError: (error: string | null) => void;
  setIsInitialized: (isInitialized: boolean) => void;
  setCurrentUser: (user: any | null) => void;

  // Data actions
  fetchRecipients: () => Promise<void>;
  addRecipient: (recipientData: { fullName: string; phoneNumber: string }) => Promise<void>;
  updateRecipient: (recipientId: string, updates: { fullName?: string; phoneNumber?: string }) => Promise<void>;
  deleteRecipient: (recipientId: string) => Promise<void>;
  refreshRecipients: () => Promise<void>;
  ensureRecipientDetail: (recipientId: string) => void;
  refreshRecipientDetail: (recipientId: string) => Promise<Recipient | null>;
  invalidateRecipientDetail: (recipientId: string) => Promise<Recipient | null>;
  removeRecipientDetail: (recipientId: string) => void;
  clearRecipientDetails: () => void;

  // Error clearing
  clearErrors: () => void;
  clearAddError: () => void;
  clearUpdateError: () => void;
  clearDeleteError: () => void;

  // Initialize
  initialize: (user: any | null) => Promise<void>;
}

export const useRecipientsStore = create<RecipientsState>((set, get) => ({
  // Initial state
  recipients: [],
  recipientDetails: {},
  loading: false,
  error: null,
  addError: null,
  updateError: null,
  deleteError: null,
  isInitialized: false,
  currentUser: null,

  // Setters
  setRecipients: (recipients) => set({ recipients }),
  setLoading: (loading) => set({ loading }),
  setError: (error) => set({ error }),
  setAddError: (addError) => set({ addError }),
  setUpdateError: (updateError) => set({ updateError }),
  setDeleteError: (deleteError) => set({ deleteError }),
  setIsInitialized: (isInitialized) => set({ isInitialized }),
  setCurrentUser: (currentUser) => set({ currentUser }),

  // Fetch recipients
  fetchRecipients: async () => {
    const { currentUser } = get();

    if (!currentUser?.uid) {
      set({ recipients: [], recipientDetails: {}, error: null, isInitialized: true });
      return;
    }

    set({ loading: true, error: null });

    try {
      const userRecipients = await RecipientService.getUserRecipients(currentUser.uid);
      const normalizedRecipients = userRecipients
        .map((recipient) => normalizeRecipient(recipient))
        .filter((recipient): recipient is Recipient => recipient !== null);

      set((state) => {
        const nextDetails = { ...state.recipientDetails };
        normalizedRecipients.forEach((recipient) => {
          const detailEntry = nextDetails[recipient.id];
          if (detailEntry) {
            nextDetails[recipient.id] = buildDetailEntry(detailEntry, {
              recipient,
              loading: false,
              error: null,
              lastFetched: Date.now(),
            });
          }
        });

        return {
          recipients: normalizedRecipients,
          recipientDetails: nextDetails,
        };
      });
    } catch (err) {
      console.error('Error fetching recipients:', err);
      set({
        error: err instanceof Error ? err.message : 'Failed to fetch recipients',
        recipients: [],
        recipientDetails: {},
      });
    } finally {
      set({ loading: false, isInitialized: true });
    }
  },

  // Add recipient
  addRecipient: async (recipientData: { fullName: string; phoneNumber: string }) => {
    const { currentUser } = get();

    if (!currentUser?.uid) {
      set({ addError: 'User not found' });
      return;
    }

    set({ loading: true, addError: null });

    try {
      const result = await withGlobalLoading(() => RecipientService.addRecipient(currentUser.uid, recipientData));
      if (!result.success) {
        set({ addError: result.error || 'Failed to add recipient' });
        return;
      }

      await get().fetchRecipients();
      if (result.recipientId) {
        await get().invalidateRecipientDetail(result.recipientId);
      }
    } catch (err) {
      set({ addError: err instanceof Error ? err.message : 'Failed to add recipient' });
    } finally {
      set({ loading: false });
    }
  },

  // Update recipient
  updateRecipient: async (recipientId: string, updates: { fullName?: string; phoneNumber?: string }) => {
    set({ loading: true, updateError: null });

    try {
      const result = await withGlobalLoading(() => RecipientService.updateRecipient(recipientId, updates));
      if (!result.success) {
        set({ updateError: result.error || 'Failed to update recipient' });
        return;
      }

      await get().fetchRecipients();
      await get().invalidateRecipientDetail(recipientId);
    } catch (err) {
      set({ updateError: err instanceof Error ? err.message : 'Failed to update recipient' });
    } finally {
      set({ loading: false });
    }
  },

  // Delete recipient
  deleteRecipient: async (recipientId: string) => {
    set({ loading: true, deleteError: null });

    try {
      const result = await withGlobalLoading(() => RecipientService.deleteRecipient(recipientId));
      if (!result.success) {
        set({ deleteError: result.error || 'Failed to delete recipient' });
        return;
      }

      await get().fetchRecipients();
      get().removeRecipientDetail(recipientId);
    } catch (err) {
      set({ deleteError: err instanceof Error ? err.message : 'Failed to delete recipient' });
    } finally {
      set({ loading: false });
    }
  },

  // Refresh recipients
  refreshRecipients: async () => {
    await get().fetchRecipients();
  },

  ensureRecipientDetail: (recipientId: string) => {
    if (!recipientId) {
      return;
    }

    const existing = get().recipientDetails[recipientId];
    if (existing?.loading) {
      return;
    }

    if (existing?.lastFetched) {
      return;
    }

    void get().refreshRecipientDetail(recipientId).catch((error) => {
      set((state) => ({
        recipientDetails: {
          ...state.recipientDetails,
          [recipientId]: buildDetailEntry(state.recipientDetails[recipientId], {
            loading: false,
            error: error instanceof Error ? error.message : 'Failed to fetch recipient',
          }),
        },
      }));
    });
  },

  refreshRecipientDetail: async (recipientId: string) => {
    if (!recipientId) {
      return null;
    }

    set((state) => ({
      recipientDetails: {
        ...state.recipientDetails,
        [recipientId]: buildDetailEntry(state.recipientDetails[recipientId], {
          loading: true,
          error: null,
        }),
      },
    }));

    try {
      const docRef = doc('recipients', recipientId);
      const docSnap = await docRef.get();
      const recipient = normalizeRecipient(snapshotExists(docSnap) ? (docSnap.data() as Recipient) : null);

      set((state) => ({
        recipientDetails: {
          ...state.recipientDetails,
          [recipientId]: buildDetailEntry(state.recipientDetails[recipientId], {
            recipient,
            loading: false,
            error: recipient ? null : 'Recipient not found',
            lastFetched: Date.now(),
          }),
        },
      }));

      return recipient;
    } catch (error) {
      set((state) => ({
        recipientDetails: {
          ...state.recipientDetails,
          [recipientId]: buildDetailEntry(state.recipientDetails[recipientId], {
            loading: false,
            error: error instanceof Error ? error.message : 'Failed to fetch recipient',
          }),
        },
      }));
      throw error;
    }
  },

  invalidateRecipientDetail: async (recipientId: string) => {
    if (!recipientId) {
      return null;
    }

    set((state) => ({
      recipientDetails: {
        ...state.recipientDetails,
        [recipientId]: buildDetailEntry(state.recipientDetails[recipientId], {
          loading: true,
          error: null,
          lastFetched: undefined,
        }),
      },
    }));

    return get().refreshRecipientDetail(recipientId);
  },

  removeRecipientDetail: (recipientId: string) => {
    set((state) => {
      const { [recipientId]: _removed, ...rest } = state.recipientDetails;
      return { recipientDetails: rest };
    });
  },

  clearRecipientDetails: () => {
    set({ recipientDetails: {} });
  },

  // Error clearing
  clearErrors: () => set({
    error: null,
    addError: null,
    updateError: null,
    deleteError: null,
  }),

  clearAddError: () => set({ addError: null }),
  clearUpdateError: () => set({ updateError: null }),
  clearDeleteError: () => set({ deleteError: null }),

  // Initialize
  initialize: async (user: any | null) => {
    const previousUser = get().currentUser;

    if (previousUser?.uid && previousUser.uid !== user?.uid) {
      get().clearRecipientDetails();
      set({ recipients: [] });
    }

    set({ currentUser: user });

    if (user?.uid) {
      await get().fetchRecipients();
    } else {
      get().clearRecipientDetails();
      set({ recipients: [], error: null, isInitialized: true });
    }
  },
}));

export const getRecipientDetailFromCache = (recipientId: string): Recipient | null => {
  if (!recipientId) {
    return null;
  }
  return useRecipientsStore.getState().recipientDetails[recipientId]?.recipient ?? null;
};
