/**
 * Push Notifications Service
 *
 * Handles push notification registration, permissions, and management
 */

import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
import { Platform } from 'react-native';
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';

// Types
export interface PushNotification {
  id: string;
  title: string;
  body: string;
  data?: Record<string, any>;
  receivedAt: number;
  read: boolean;
}

interface NotificationState {
  pushToken: string | null;
  permissions: {
    granted: boolean;
    canAskAgain: boolean;
  };
  notifications: PushNotification[];
  unreadCount: number;
}

interface NotificationActions {
  setPushToken: (token: string | null) => void;
  setPermissions: (permissions: { granted: boolean; canAskAgain: boolean }) => void;
  addNotification: (notification: PushNotification) => void;
  markAsRead: (id: string) => void;
  markAllAsRead: () => void;
  removeNotification: (id: string) => void;
  clearAll: () => void;
}

// Configure notification behavior
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: true,
    shouldSetBadge: true,
    shouldShowBanner: true,
    shouldShowList: true,
  }),
});

// Notification Store
export const useNotificationStore = create<NotificationState & NotificationActions>()(
  persist(
    (set, get) => ({
      // State
      pushToken: null,
      permissions: {
        granted: false,
        canAskAgain: true,
      },
      notifications: [],
      unreadCount: 0,

      // Actions
      setPushToken: (token) => set({ pushToken: token }),

      setPermissions: (permissions) => set({ permissions }),

      addNotification: (notification) =>
        set((state) => ({
          notifications: [notification, ...state.notifications].slice(0, 50), // Keep last 50
          unreadCount: state.unreadCount + 1,
        })),

      markAsRead: (id) =>
        set((state) => {
          const notification = state.notifications.find((n) => n.id === id);
          if (!notification || notification.read) return state;

          return {
            notifications: state.notifications.map((n) =>
              n.id === id ? { ...n, read: true } : n
            ),
            unreadCount: Math.max(0, state.unreadCount - 1),
          };
        }),

      markAllAsRead: () =>
        set((state) => ({
          notifications: state.notifications.map((n) => ({ ...n, read: true })),
          unreadCount: 0,
        })),

      removeNotification: (id) =>
        set((state) => {
          const notification = state.notifications.find((n) => n.id === id);
          const unreadDelta = notification && !notification.read ? 1 : 0;

          return {
            notifications: state.notifications.filter((n) => n.id !== id),
            unreadCount: Math.max(0, state.unreadCount - unreadDelta),
          };
        }),

      clearAll: () => set({ notifications: [], unreadCount: 0 }),
    }),
    {
      name: 'notifications-storage',
      storage: createJSONStorage(() => AsyncStorage),
      partialize: (state) => ({
        notifications: state.notifications,
        unreadCount: state.unreadCount,
      }),
    }
  )
);

// Notification Service
export const notificationService = {
  // Register for push notifications
  register: async (): Promise<string | null> => {
    let token: string | null = null;

    if (!Device.isDevice) {
      console.warn('Push notifications only work on physical devices');
      return null;
    }

    // Check permissions
    const { status: existingStatus } = await Notifications.getPermissionsAsync();
    let finalStatus = existingStatus;

    if (existingStatus !== 'granted') {
      const { status } = await Notifications.requestPermissionsAsync();
      finalStatus = status;
    }

    useNotificationStore.getState().setPermissions({
      granted: finalStatus === 'granted',
      canAskAgain: finalStatus !== 'denied',
    });

    if (finalStatus !== 'granted') {
      console.warn('Push notification permission denied');
      return null;
    }

    // Get push token
    try {
      const tokenData = await Notifications.getExpoPushTokenAsync({
        projectId: process.env.EXPO_PUBLIC_PROJECT_ID,
      });
      token = tokenData.data;
      useNotificationStore.getState().setPushToken(token);
    } catch (error) {
      console.error('Error getting push token:', error);
    }

    // Configure Android channel
    if (Platform.OS === 'android') {
      await Notifications.setNotificationChannelAsync('default', {
        name: 'Default',
        importance: Notifications.AndroidImportance.MAX,
        vibrationPattern: [0, 250, 250, 250],
        lightColor: '#1e40af',
      });

      await Notifications.setNotificationChannelAsync('alerts', {
        name: 'Alerts',
        description: 'Important alerts and reminders',
        importance: Notifications.AndroidImportance.HIGH,
        vibrationPattern: [0, 500, 250, 500],
        lightColor: '#dc2626',
      });

      await Notifications.setNotificationChannelAsync('sync', {
        name: 'Sync',
        description: 'Sync status notifications',
        importance: Notifications.AndroidImportance.LOW,
        vibrationPattern: [0, 100],
        lightColor: '#059669',
      });
    }

    return token;
  },

  // Schedule local notification
  scheduleLocal: async (
    title: string,
    body: string,
    options?: {
      data?: Record<string, any>;
      trigger?: Notifications.NotificationTriggerInput;
      channelId?: string;
    }
  ): Promise<string> => {
    const id = await Notifications.scheduleNotificationAsync({
      content: {
        title,
        body,
        data: options?.data,
        sound: true,
        badge: useNotificationStore.getState().unreadCount + 1,
        ...(Platform.OS === 'android' && {
          channelId: options?.channelId || 'default',
        }),
      },
      trigger: options?.trigger || null,
    });

    return id;
  },

  // Cancel scheduled notification
  cancelScheduled: async (id: string): Promise<void> => {
    await Notifications.cancelScheduledNotificationAsync(id);
  },

  // Cancel all scheduled notifications
  cancelAllScheduled: async (): Promise<void> => {
    await Notifications.cancelAllScheduledNotificationsAsync();
  },

  // Get all scheduled notifications
  getScheduled: async (): Promise<Notifications.NotificationRequest[]> => {
    return await Notifications.getAllScheduledNotificationsAsync();
  },

  // Dismiss all presented notifications
  dismissAll: async (): Promise<void> => {
    await Notifications.dismissAllNotificationsAsync();
  },

  // Set badge count
  setBadgeCount: async (count: number): Promise<void> => {
    await Notifications.setBadgeCountAsync(count);
  },

  // Get badge count
  getBadgeCount: async (): Promise<number> => {
    return await Notifications.getBadgeCountAsync();
  },

  // Add notification listener
  addNotificationReceivedListener: (
    callback: (notification: Notifications.Notification) => void
  ): Notifications.Subscription => {
    return Notifications.addNotificationReceivedListener(callback);
  },

  // Add response listener (when user taps notification)
  addNotificationResponseListener: (
    callback: (response: Notifications.NotificationResponse) => void
  ): Notifications.Subscription => {
    return Notifications.addNotificationResponseReceivedListener(callback);
  },

  // Get last notification response
  getLastResponse: async (): Promise<Notifications.NotificationResponse | null> => {
    return await Notifications.getLastNotificationResponseAsync();
  },
};

// Helper to generate notification ID
export const generateNotificationId = () =>
  `notif_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
