import { renderHook, act } from '@testing-library/react-native';
import { PermissionsAndroid, Platform } from 'react-native';
import PushNotification from 'react-native-push-notification';
import { useNotification } from '../useNotifications';

// Mock des modules natifs
jest.mock('react-native', () => ({
  Platform: {
    OS: 'android',
    Version: 33,
  },
  PermissionsAndroid: {
    request: jest.fn().mockResolvedValue('granted'),
    PERMISSIONS: {
      POST_NOTIFICATIONS: 'android.permission.POST_NOTIFICATIONS',
    },
    RESULTS: {
      GRANTED: 'granted',
    },
  },
}));

// Mock de react-native-push-notification
jest.mock('react-native-push-notification', () => {
  return {
    configure: jest.fn(),
    createChannel: jest.fn((channel, callback) => callback(true)),
    localNotification: jest.fn(),
    cancelLocalNotification: jest.fn(),
    Importance: {
      HIGH: 4,
    },
  };
});

// Typage des mocks pour TypeScript
const mockPushNotification = PushNotification as jest.Mocked<typeof PushNotification> & {
  Importance: { HIGH: number };
};

// Mock de console.log pour éviter de polluer les logs de test
console.log = jest.fn();

describe('useNotification hook', () => {
  const notificationId = '123';
  const channelInformations = {
    channelId: 'testChannel',
    channelName: 'Test Channel',
    channelDescription: 'Channel for testing',
  };

  // Réinitialiser les mocks après chaque test
  afterEach(() => {
    jest.clearAllMocks();
  });

  it('devrait demander les permissions de notification au montage sur Android >= 33', async () => {
    renderHook(() => useNotification(notificationId, channelInformations));

    // Vérifier que la demande de permission a été appelée
    expect(PermissionsAndroid.request).toHaveBeenCalledWith(
      PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
    );
  });

  it('ne devrait pas demander les permissions sur iOS', async () => {
    Platform.OS = 'ios';

    renderHook(() => useNotification(notificationId, channelInformations));

    expect(PermissionsAndroid.request).not.toHaveBeenCalled();

    // Réinitialiser pour les tests suivants
    Platform.OS = 'android';
  });

  it('devrait configurer PushNotification au montage', () => {
    renderHook(() => useNotification(notificationId, channelInformations));

    expect(mockPushNotification.configure).toHaveBeenCalled();
    const configCall = (mockPushNotification.configure as jest.Mock).mock.calls[0][0];

    // Vérifier que les fonctions de callback sont définies
    expect(typeof configCall.onRegister).toBe('function');
    expect(typeof configCall.onNotification).toBe('function');

    // Vérifier les permissions
    expect(configCall.permissions).toEqual({
      alert: true,
      badge: true,
      sound: true,
    });

    // Vérifier les autres paramètres
    expect(configCall.popInitialNotification).toBe(true);
    expect(configCall.requestPermissions).toBe(Platform.OS === 'ios');
  });

  it('devrait créer un canal de notification sur Android', () => {
    renderHook(() => useNotification(notificationId, channelInformations));

    expect(mockPushNotification.createChannel).toHaveBeenCalledWith(
      {
        ...channelInformations,
        vibrate: true,
        importance: mockPushNotification.Importance.HIGH,
      },
      expect.any(Function)
    );
  });

  it('ne devrait pas créer de canal sur iOS', () => {
    Platform.OS = 'ios';

    renderHook(() => useNotification(notificationId, channelInformations));

    expect(mockPushNotification.createChannel).not.toHaveBeenCalled();

    // Réinitialiser pour les tests suivants
    Platform.OS = 'android';
  });

  it('devrait retourner les fonctions updateNotification et cancelNotification', () => {
    const { result } = renderHook(() => useNotification(notificationId, channelInformations));

    expect(result.current).toHaveProperty('updateNotification');
    expect(result.current).toHaveProperty('cancelNotification');
    expect(typeof result.current.updateNotification).toBe('function');
    expect(typeof result.current.cancelNotification).toBe('function');
  });

  it('updateNotification devrait appeler localNotification avec les bons paramètres', () => {
    const { result } = renderHook(() => useNotification(notificationId, channelInformations));

    act(() => {
      result.current.updateNotification('Test Title', 'Test Message');
    });

    expect(mockPushNotification.localNotification).toHaveBeenCalledWith({
      channelId: channelInformations.channelId,
      id: parseInt(notificationId),
      title: 'Test Title',
      message: 'Test Message',
      playSound: false,
      vibrate: false,
      ongoing: true,
      priority: 'high',
      importance: 'high',
      onlyAlertOnce: true,
    });
  });

  it('cancelNotification devrait appeler cancelLocalNotification avec le bon ID', () => {
    const { result } = renderHook(() => useNotification(notificationId, channelInformations));

    act(() => {
      result.current.cancelNotification();
    });

    expect(mockPushNotification.cancelLocalNotification).toHaveBeenCalledWith(notificationId);
  });
});
