import AsyncStorage from '@react-native-async-storage/async-storage';
import { timerStore, TimerState } from '../TimerStore';

// Mock AsyncStorage with correct typing for Jest
jest.mock('@react-native-async-storage/async-storage', () => ({
  setItem: jest.fn(() => Promise.resolve()),
  getItem: jest.fn(() => Promise.resolve(null)),
}));

// Add type for mocked functions
const mockedAsyncStorage = AsyncStorage as jest.Mocked<typeof AsyncStorage>;

describe('TimerStore', () => {
  // Tests pour savePreparationTime method
  describe('savePreparationTime', () => {
    test('should save preparation time in AsyncStorage', async () => {
      await timerStore.savePreparationTime(5);
      expect(mockedAsyncStorage.setItem).toHaveBeenCalledWith('timer_preparation_time', '5');
    });

    test('should handle errors when saving preparation time', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.setItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      await timerStore.savePreparationTime(5);

      expect(consoleSpy).toHaveBeenCalledWith(
        'Error saving preparation time:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });

  // Clear all mocks after each test
  afterEach(() => {
    jest.clearAllMocks();
  });

  // Tests for saveReps method
  describe('saveReps', () => {
    test('should save repetitions in AsyncStorage', async () => {
      await timerStore.saveReps(5);
      expect(mockedAsyncStorage.setItem).toHaveBeenCalledWith('timer_reps', '5');
    });

    test('should handle errors when saving repetitions', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.setItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      await timerStore.saveReps(3);

      expect(consoleSpy).toHaveBeenCalledWith(
        'Error saving repetitions:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });

  // Tests for saveWorkTime method
  describe('saveWorkTime', () => {
    test('should save work time in AsyncStorage', async () => {
      await timerStore.saveWorkTime(30);
      expect(mockedAsyncStorage.setItem).toHaveBeenCalledWith('timer_work_time', '30');
    });

    test('should handle errors when saving work time', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.setItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      await timerStore.saveWorkTime(30);

      expect(consoleSpy).toHaveBeenCalledWith(
        'Error saving work time:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });

  // Tests for saveRestTime method
  describe('saveRestTime', () => {
    test('should save rest time in AsyncStorage', async () => {
      await timerStore.saveRestTime(15);
      expect(mockedAsyncStorage.setItem).toHaveBeenCalledWith('timer_rest_time', '15');
    });

    test('should handle errors when saving rest time', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.setItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      await timerStore.saveRestTime(15);

      expect(consoleSpy).toHaveBeenCalledWith(
        'Error saving rest time:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });

  // Tests for saveState method
  describe('saveState', () => {
    test('should save complete state in AsyncStorage', async () => {
      const state: TimerState = {
        reps: 3,
        workTime: 40,
        restTime: 20,
        preparationTime: 5
      };

      await timerStore.saveState(state);

      expect(mockedAsyncStorage.setItem).toHaveBeenCalledWith('timer_reps', '3');
      expect(mockedAsyncStorage.setItem).toHaveBeenCalledWith('timer_work_time', '40');
      expect(mockedAsyncStorage.setItem).toHaveBeenCalledWith('timer_rest_time', '20');
      expect(mockedAsyncStorage.setItem).toHaveBeenCalledWith('timer_preparation_time', '5');
    });

    test('should handle errors when saving state', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.setItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      const state: TimerState = {
        reps: 3,
        workTime: 40,
        restTime: 20,
        preparationTime: 3
      };

      await timerStore.saveState(state);

      expect(consoleSpy).toHaveBeenCalledWith(
        'Error saving repetitions:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });

  // Tests for getReps method
  describe('getReps', () => {
    test('should retrieve repetitions from AsyncStorage', async () => {
      mockedAsyncStorage.getItem.mockResolvedValueOnce('5');

      const result = await timerStore.getReps();

      expect(result).toBe(5);
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_reps');
    });

    test('should return default value if no data is found', async () => {
      mockedAsyncStorage.getItem.mockResolvedValueOnce(null);

      const result = await timerStore.getReps();

      expect(result).toBe(1); // Default value
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_reps');
    });

    test('should handle errors when retrieving repetitions', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.getItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      const result = await timerStore.getReps();

      expect(result).toBe(1); // Default value
      expect(consoleSpy).toHaveBeenCalledWith(
        'Error retrieving repetitions:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });

  // Tests for getPreparationTime method
  describe('getPreparationTime', () => {
    test('should retrieve preparation time from AsyncStorage', async () => {
      mockedAsyncStorage.getItem.mockResolvedValueOnce('5');

      const result = await timerStore.getPreparationTime();

      expect(result).toBe(5);
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_preparation_time');
    });

    test('should return default value if no data is found', async () => {
      mockedAsyncStorage.getItem.mockResolvedValueOnce(null);

      const result = await timerStore.getPreparationTime();

      expect(result).toBe(3); // Default preparation time value
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_preparation_time');
    });

    test('should handle errors when retrieving preparation time', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.getItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      const result = await timerStore.getPreparationTime();

      expect(result).toBe(3); // Default value
      expect(consoleSpy).toHaveBeenCalledWith(
        'Error retrieving preparation time:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });

  // Tests for getWorkTime method
  describe('getWorkTime', () => {
    test('should retrieve work time from AsyncStorage', async () => {
      mockedAsyncStorage.getItem.mockResolvedValueOnce('30');

      const result = await timerStore.getWorkTime();

      expect(result).toBe(30);
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_work_time');
    });

    test('should return default value if no data is found', async () => {
      mockedAsyncStorage.getItem.mockResolvedValueOnce(null);

      const result = await timerStore.getWorkTime();

      expect(result).toBe(0); // Default value
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_work_time');
    });

    test('should handle errors when retrieving work time', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.getItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      const result = await timerStore.getWorkTime();

      expect(result).toBe(0); // Default value
      expect(consoleSpy).toHaveBeenCalledWith(
        'Error retrieving work time:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });

  // Tests for getRestTime method
  describe('getRestTime', () => {
    test('should retrieve rest time from AsyncStorage', async () => {
      mockedAsyncStorage.getItem.mockResolvedValueOnce('15');

      const result = await timerStore.getRestTime();

      expect(result).toBe(15);
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_rest_time');
    });

    test('should return default value if no data is found', async () => {
      mockedAsyncStorage.getItem.mockResolvedValueOnce(null);

      const result = await timerStore.getRestTime();

      expect(result).toBe(0); // Default value
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_rest_time');
    });

    test('should handle errors when retrieving rest time', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.getItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      const result = await timerStore.getRestTime();

      expect(result).toBe(0); // Default value
      expect(consoleSpy).toHaveBeenCalledWith(
        'Error retrieving rest time:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });

  // Tests for getState method
  describe('getState', () => {
    test('should retrieve complete state from AsyncStorage', async () => {
      mockedAsyncStorage.getItem
        .mockResolvedValueOnce('3') // reps
        .mockResolvedValueOnce('40') // workTime
        .mockResolvedValueOnce('20') // restTime
        .mockResolvedValueOnce('5'); // preparationTime

      const result = await timerStore.getState();

      expect(result).toEqual({
        reps: 3,
        workTime: 40,
        restTime: 20,
        preparationTime: 5
      });

      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_reps');
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_work_time');
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_rest_time');
      expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_preparation_time');
    });

    test('should handle errors when retrieving state', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
      mockedAsyncStorage.getItem.mockRejectedValueOnce(new Error('AsyncStorage Error'));

      const result = await timerStore.getState();

      expect(result).toEqual({
        reps: 1,
        workTime: 0,
        restTime: 0,
        preparationTime: 3
      }); // Default values

      expect(consoleSpy).toHaveBeenCalledWith(
        'Error retrieving repetitions:',
        expect.any(Error)
      );
      consoleSpy.mockRestore();
    });
  });
});
