import { fromJS } from 'immutable';
import {
  makeSelectMobilePushNew,
  makeSelectUploadedAssetData,
  makeSelectUploadedAssetData0,
  makeSelectUploadedAssetData1,
  makeSelectUploadAssetSuccess,
  makeSelectCreateError,
  makeSelectAssetUploading,
  makeSelectGetTemplateDetailsInProgress,
} from '../selectors';

describe('MobilePushNew selectors', () => {
  // Mock state structures
  const mockMobilePushNewState = {
    uploadedAssetData: { id: 1, url: 'test-url' },
    uploadedAssetData0: { id: 10, url: 'test-url-0', platform: 'android' },
    uploadedAssetData1: { id: 11, url: 'test-url-1', platform: 'ios' },
    uploadAssetSuccess: true,
    createTemplateErrorMessage: 'Test error message',
    assetUploading: true,
    getTemplateDetailsInProgress: true,
    otherProperty: 'test-value',
  };

  const mockStateWithMobilePushNew = fromJS({
    mobilePushNew: mockMobilePushNewState,
    otherState: { value: 'test' },
  });

  const mockStateWithoutMobilePushNew = fromJS({
    otherState: { value: 'test' },
  });

  const mockStateWithEmptyMobilePushNew = fromJS({
    mobilePushNew: {},
    otherState: { value: 'test' },
  });

  const mockStateWithPartialMobilePushNew = fromJS({
    mobilePushNew: {
      uploadedAssetData: { id: 2, name: 'test-asset' },
      uploadedAssetData0: { id: 20, name: 'test-asset-0' },
      uploadAssetSuccess: false,
      // Missing other properties to test defaults
    },
    otherState: { value: 'test' },
  });

  describe('makeSelectMobilePushNew', () => {
    it('should select the mobilePushNew state and convert to JS', () => {
      const selector = makeSelectMobilePushNew();
      const result = selector(mockStateWithMobilePushNew);

      expect(result).toEqual(mockMobilePushNewState);
      expect(typeof result).toBe('object');
      expect(Array.isArray(result)).toBe(false);
    });

    it('should return empty object when mobilePushNew state does not exist', () => {
      const selector = makeSelectMobilePushNew();
      const result = selector(mockStateWithoutMobilePushNew);

      expect(result).toEqual({});
    });

    it('should return empty object when mobilePushNew state is empty', () => {
      const selector = makeSelectMobilePushNew();
      const result = selector(mockStateWithEmptyMobilePushNew);

      expect(result).toEqual({});
    });

    it('should handle partial mobilePushNew state', () => {
      const selector = makeSelectMobilePushNew();
      const result = selector(mockStateWithPartialMobilePushNew);

      expect(result).toEqual({
        uploadedAssetData: { id: 2, name: 'test-asset' },
        uploadedAssetData0: { id: 20, name: 'test-asset-0' },
        uploadAssetSuccess: false,
      });
    });
  });

  describe('makeSelectUploadedAssetData', () => {
    it('should select uploadedAssetData when it exists', () => {
      const selector = makeSelectUploadedAssetData();
      const result = selector(mockStateWithMobilePushNew);

      // The selector returns the Immutable object directly, not converted to JS
      expect(result.get('id')).toBe(1);
      expect(result.get('url')).toBe('test-url');
    });

    it('should return empty object when uploadedAssetData does not exist', () => {
      const selector = makeSelectUploadedAssetData();
      const result = selector(mockStateWithoutMobilePushNew);

      expect(result).toEqual({});
    });

    it('should return empty object when mobilePushNew state is empty', () => {
      const selector = makeSelectUploadedAssetData();
      const result = selector(mockStateWithEmptyMobilePushNew);

      expect(result).toEqual({});
    });

    it('should return uploadedAssetData from partial state', () => {
      const selector = makeSelectUploadedAssetData();
      const result = selector(mockStateWithPartialMobilePushNew);

      // The selector returns the Immutable object directly
      expect(result.get('id')).toBe(2);
      expect(result.get('name')).toBe('test-asset');
    });

    it('should return empty object when uploadedAssetData is null', () => {
      const stateWithNullAssetData = fromJS({
        mobilePushNew: {
          uploadedAssetData: null,
          uploadAssetSuccess: true,
        },
      });

      const selector = makeSelectUploadedAssetData();
      const result = selector(stateWithNullAssetData);

      expect(result).toEqual({});
    });
  });

  describe('makeSelectUploadedAssetData0', () => {
    it('should select uploadedAssetData0 when it exists', () => {
      const selector = makeSelectUploadedAssetData0();
      const result = selector(mockStateWithMobilePushNew);

      // The selector returns the Immutable object directly, not converted to JS
      expect(result.get('id')).toBe(10);
      expect(result.get('url')).toBe('test-url-0');
      expect(result.get('platform')).toBe('android');
    });

    it('should return empty object when uploadedAssetData0 does not exist', () => {
      const selector = makeSelectUploadedAssetData0();
      const result = selector(mockStateWithoutMobilePushNew);

      expect(result).toEqual({});
    });

    it('should return empty object when mobilePushNew state is empty', () => {
      const selector = makeSelectUploadedAssetData0();
      const result = selector(mockStateWithEmptyMobilePushNew);

      expect(result).toEqual({});
    });

    it('should return uploadedAssetData0 from partial state', () => {
      const selector = makeSelectUploadedAssetData0();
      const result = selector(mockStateWithPartialMobilePushNew);

      // The selector returns the Immutable object directly
      expect(result.get('id')).toBe(20);
      expect(result.get('name')).toBe('test-asset-0');
    });

    it('should return empty object when uploadedAssetData0 is null', () => {
      const stateWithNullAssetData0 = fromJS({
        mobilePushNew: {
          uploadedAssetData0: null,
          uploadAssetSuccess: true,
        },
      });

      const selector = makeSelectUploadedAssetData0();
      const result = selector(stateWithNullAssetData0);

      expect(result).toEqual({});
    });

    it('should handle uploadedAssetData0 with complex nested data', () => {
      const stateWithComplexAssetData0 = fromJS({
        mobilePushNew: {
          uploadedAssetData0: {
            id: 30,
            metaInfo: {
              secure_file_path: '/path/to/file.jpg',
              duration: 10.5,
              file_size: 1024000,
            },
            status: 'uploaded',
          },
        },
      });

      const selector = makeSelectUploadedAssetData0();
      const result = selector(stateWithComplexAssetData0);

      expect(result.get('id')).toBe(30);
      expect(result.getIn(['metaInfo', 'secure_file_path'])).toBe('/path/to/file.jpg');
      expect(result.getIn(['metaInfo', 'duration'])).toBe(10.5);
      expect(result.getIn(['metaInfo', 'file_size'])).toBe(1024000);
      expect(result.get('status')).toBe('uploaded');
    });

    it('should handle uploadedAssetData0 with empty object', () => {
      const stateWithEmptyAssetData0 = fromJS({
        mobilePushNew: {
          uploadedAssetData0: {},
        },
      });

      const selector = makeSelectUploadedAssetData0();
      const result = selector(stateWithEmptyAssetData0);

      expect(result).toEqual(fromJS({}));
    });
  });

  describe('makeSelectUploadedAssetData1', () => {
    it('should select uploadedAssetData1 when it exists', () => {
      const selector = makeSelectUploadedAssetData1();
      const result = selector(mockStateWithMobilePushNew);

      // The selector returns the Immutable object directly, not converted to JS
      expect(result.get('id')).toBe(11);
      expect(result.get('url')).toBe('test-url-1');
      expect(result.get('platform')).toBe('ios');
    });

    it('should return empty object when uploadedAssetData1 does not exist', () => {
      const selector = makeSelectUploadedAssetData1();
      const result = selector(mockStateWithoutMobilePushNew);

      expect(result).toEqual({});
    });

    it('should return empty object when mobilePushNew state is empty', () => {
      const selector = makeSelectUploadedAssetData1();
      const result = selector(mockStateWithEmptyMobilePushNew);

      expect(result).toEqual({});
    });

    it('should return empty object when uploadedAssetData1 is not in partial state', () => {
      const selector = makeSelectUploadedAssetData1();
      const result = selector(mockStateWithPartialMobilePushNew);

      expect(result).toEqual({});
    });

    it('should return empty object when uploadedAssetData1 is null', () => {
      const stateWithNullAssetData1 = fromJS({
        mobilePushNew: {
          uploadedAssetData1: null,
          uploadAssetSuccess: true,
        },
      });

      const selector = makeSelectUploadedAssetData1();
      const result = selector(stateWithNullAssetData1);

      expect(result).toEqual({});
    });

    it('should handle uploadedAssetData1 with complex nested data', () => {
      const stateWithComplexAssetData1 = fromJS({
        mobilePushNew: {
          uploadedAssetData1: {
            id: 31,
            metaInfo: {
              secure_file_path: '/path/to/video.mp4',
              duration: 15.2,
              file_size: 2048000,
              video_preview: '/path/to/preview.jpg',
            },
            status: 'processing',
            uploadProgress: 100,
          },
        },
      });

      const selector = makeSelectUploadedAssetData1();
      const result = selector(stateWithComplexAssetData1);

      expect(result.get('id')).toBe(31);
      expect(result.getIn(['metaInfo', 'secure_file_path'])).toBe('/path/to/video.mp4');
      expect(result.getIn(['metaInfo', 'duration'])).toBe(15.2);
      expect(result.getIn(['metaInfo', 'file_size'])).toBe(2048000);
      expect(result.getIn(['metaInfo', 'video_preview'])).toBe('/path/to/preview.jpg');
      expect(result.get('status')).toBe('processing');
      expect(result.get('uploadProgress')).toBe(100);
    });

    it('should handle uploadedAssetData1 with empty object', () => {
      const stateWithEmptyAssetData1 = fromJS({
        mobilePushNew: {
          uploadedAssetData1: {},
        },
      });

      const selector = makeSelectUploadedAssetData1();
      const result = selector(stateWithEmptyAssetData1);

      expect(result).toEqual(fromJS({}));
    });

    it('should handle uploadedAssetData1 with different data types', () => {
      const stateWithMixedDataTypes = fromJS({
        mobilePushNew: {
          uploadedAssetData1: {
            id: 32,
            name: 'test-video',
            isActive: true,
            tags: ['video', 'mobile'],
            metadata: {
              width: 1920,
              height: 1080,
              format: 'mp4',
            },
          },
        },
      });

      const selector = makeSelectUploadedAssetData1();
      const result = selector(stateWithMixedDataTypes);

      expect(result.get('id')).toBe(32);
      expect(result.get('name')).toBe('test-video');
      expect(result.get('isActive')).toBe(true);
      expect(result.get('tags').toJS()).toEqual(['video', 'mobile']);
      expect(result.getIn(['metadata', 'width'])).toBe(1920);
      expect(result.getIn(['metadata', 'height'])).toBe(1080);
      expect(result.getIn(['metadata', 'format'])).toBe('mp4');
    });
  });

  describe('makeSelectUploadAssetSuccess', () => {
    it('should select uploadAssetSuccess when it is true', () => {
      const selector = makeSelectUploadAssetSuccess();
      const result = selector(mockStateWithMobilePushNew);

      expect(result).toBe(true);
    });

    it('should select uploadAssetSuccess when it is false', () => {
      const selector = makeSelectUploadAssetSuccess();
      const result = selector(mockStateWithPartialMobilePushNew);

      expect(result).toBe(false);
    });

    it('should return false when uploadAssetSuccess does not exist', () => {
      const selector = makeSelectUploadAssetSuccess();
      const result = selector(mockStateWithoutMobilePushNew);

      expect(result).toBe(false);
    });

    it('should return false when mobilePushNew state is empty', () => {
      const selector = makeSelectUploadAssetSuccess();
      const result = selector(mockStateWithEmptyMobilePushNew);

      expect(result).toBe(false);
    });

    it('should return false when uploadAssetSuccess is null or undefined', () => {
      const stateWithNullSuccess = fromJS({
        mobilePushNew: {
          uploadAssetSuccess: null,
          uploadedAssetData: {},
        },
      });

      const selector = makeSelectUploadAssetSuccess();
      const result = selector(stateWithNullSuccess);

      expect(result).toBe(false);
    });
  });

  describe('makeSelectCreateError', () => {
    it('should select createTemplateErrorMessage when it exists', () => {
      const selector = makeSelectCreateError();
      const result = selector(mockStateWithMobilePushNew);

      expect(result).toBe('Test error message');
    });

    it('should return empty string when createTemplateErrorMessage does not exist', () => {
      const selector = makeSelectCreateError();
      const result = selector(mockStateWithoutMobilePushNew);

      expect(result).toBe('');
    });

    it('should return empty string when mobilePushNew state is empty', () => {
      const selector = makeSelectCreateError();
      const result = selector(mockStateWithEmptyMobilePushNew);

      expect(result).toBe('');
    });

    it('should return empty string when createTemplateErrorMessage is not in partial state', () => {
      const selector = makeSelectCreateError();
      const result = selector(mockStateWithPartialMobilePushNew);

      expect(result).toBe('');
    });

    it('should handle various error message types', () => {
      const stateWithErrorMessage = fromJS({
        mobilePushNew: {
          createTemplateErrorMessage: 'Network error occurred',
        },
      });

      const selector = makeSelectCreateError();
      const result = selector(stateWithErrorMessage);

      expect(result).toBe('Network error occurred');
    });

    it('should return empty string when createTemplateErrorMessage is null', () => {
      const stateWithNullError = fromJS({
        mobilePushNew: {
          createTemplateErrorMessage: null,
        },
      });

      const selector = makeSelectCreateError();
      const result = selector(stateWithNullError);

      expect(result).toBe('');
    });
  });

  describe('makeSelectAssetUploading', () => {
    it('should select assetUploading when it is true', () => {
      const selector = makeSelectAssetUploading();
      const result = selector(mockStateWithMobilePushNew);

      expect(result).toBe(true);
    });

    it('should return false when assetUploading does not exist', () => {
      const selector = makeSelectAssetUploading();
      const result = selector(mockStateWithoutMobilePushNew);

      expect(result).toBe(false);
    });

    it('should return false when mobilePushNew state is empty', () => {
      const selector = makeSelectAssetUploading();
      const result = selector(mockStateWithEmptyMobilePushNew);

      expect(result).toBe(false);
    });

    it('should return false when assetUploading is not in partial state', () => {
      const selector = makeSelectAssetUploading();
      const result = selector(mockStateWithPartialMobilePushNew);

      expect(result).toBe(false);
    });

    it('should handle assetUploading when explicitly set to false', () => {
      const stateWithFalseUploading = fromJS({
        mobilePushNew: {
          assetUploading: false,
        },
      });

      const selector = makeSelectAssetUploading();
      const result = selector(stateWithFalseUploading);

      expect(result).toBe(false);
    });

    it('should return false when assetUploading is null', () => {
      const stateWithNullUploading = fromJS({
        mobilePushNew: {
          assetUploading: null,
        },
      });

      const selector = makeSelectAssetUploading();
      const result = selector(stateWithNullUploading);

      expect(result).toBe(false);
    });
  });

  describe('makeSelectGetTemplateDetailsInProgress', () => {
    it('should select getTemplateDetailsInProgress when it is true', () => {
      const selector = makeSelectGetTemplateDetailsInProgress();
      const result = selector(mockStateWithMobilePushNew);

      expect(result).toBe(true);
    });

    it('should return false when getTemplateDetailsInProgress does not exist', () => {
      const selector = makeSelectGetTemplateDetailsInProgress();
      const result = selector(mockStateWithoutMobilePushNew);

      expect(result).toBe(false);
    });

    it('should return false when mobilePushNew state is empty', () => {
      const selector = makeSelectGetTemplateDetailsInProgress();
      const result = selector(mockStateWithEmptyMobilePushNew);

      expect(result).toBe(false);
    });

    it('should return false when getTemplateDetailsInProgress is not in partial state', () => {
      const selector = makeSelectGetTemplateDetailsInProgress();
      const result = selector(mockStateWithPartialMobilePushNew);

      expect(result).toBe(false);
    });

    it('should handle getTemplateDetailsInProgress when explicitly set to false', () => {
      const stateWithFalseProgress = fromJS({
        mobilePushNew: {
          getTemplateDetailsInProgress: false,
        },
      });

      const selector = makeSelectGetTemplateDetailsInProgress();
      const result = selector(stateWithFalseProgress);

      expect(result).toBe(false);
    });

    it('should return false when getTemplateDetailsInProgress is null', () => {
      const stateWithNullProgress = fromJS({
        mobilePushNew: {
          getTemplateDetailsInProgress: null,
        },
      });

      const selector = makeSelectGetTemplateDetailsInProgress();
      const result = selector(stateWithNullProgress);

      expect(result).toBe(false);
    });
  });

  describe('Selector memoization', () => {
    it('should return the same result for identical state (memoization test)', () => {
      const selector = makeSelectMobilePushNew();
      const result1 = selector(mockStateWithMobilePushNew);
      const result2 = selector(mockStateWithMobilePushNew);

      expect(result1).toBe(result2);
    });

    it('should return different results for different states', () => {
      const selector = makeSelectUploadAssetSuccess();
      const result1 = selector(mockStateWithMobilePushNew);
      const result2 = selector(mockStateWithPartialMobilePushNew);

      expect(result1).toBe(true);
      expect(result2).toBe(false);
      expect(result1).not.toBe(result2);
    });
  });

  describe('Edge cases', () => {
    it('should handle undefined state gracefully', () => {
      const selector = makeSelectMobilePushNew();
      const undefinedState = fromJS({});
      const result = selector(undefinedState);

      expect(result).toEqual({});
    });

    it('should handle state with mobilePushNew as null', () => {
      const stateWithNullMobilePushNew = fromJS({
        mobilePushNew: null,
      });

      const selector = makeSelectUploadedAssetData();
      const result = selector(stateWithNullMobilePushNew);

      expect(result).toEqual({});
    });

    it('should handle deeply nested state access', () => {
      const complexState = fromJS({
        level1: {
          level2: {
            mobilePushNew: mockMobilePushNewState,
          },
        },
      });

      // This should return defaults since mobilePushNew is not at root level
      const selector = makeSelectUploadAssetSuccess();
      const result = selector(complexState);

      expect(result).toBe(false);
    });
  });

  describe('Multiple selector usage', () => {
    it('should work correctly when multiple selectors are used on same state', () => {
      const successSelector = makeSelectUploadAssetSuccess();
      const uploadingSelector = makeSelectAssetUploading();
      const errorSelector = makeSelectCreateError();
      const assetData0Selector = makeSelectUploadedAssetData0();
      const assetData1Selector = makeSelectUploadedAssetData1();

      const successResult = successSelector(mockStateWithMobilePushNew);
      const uploadingResult = uploadingSelector(mockStateWithMobilePushNew);
      const errorResult = errorSelector(mockStateWithMobilePushNew);
      const assetData0Result = assetData0Selector(mockStateWithMobilePushNew);
      const assetData1Result = assetData1Selector(mockStateWithMobilePushNew);

      expect(successResult).toBe(true);
      expect(uploadingResult).toBe(true);
      expect(errorResult).toBe('Test error message');
      expect(assetData0Result.get('id')).toBe(10);
      expect(assetData0Result.get('platform')).toBe('android');
      expect(assetData1Result.get('id')).toBe(11);
      expect(assetData1Result.get('platform')).toBe('ios');
    });

    it('should maintain independent results across different selectors', () => {
      const assetDataSelector = makeSelectUploadedAssetData();
      const assetData0Selector = makeSelectUploadedAssetData0();
      const progressSelector = makeSelectGetTemplateDetailsInProgress();

      const assetDataResult = assetDataSelector(mockStateWithPartialMobilePushNew);
      const assetData0Result = assetData0Selector(mockStateWithPartialMobilePushNew);
      const progressResult = progressSelector(mockStateWithPartialMobilePushNew);

      // Check that assetDataResult is an Immutable object with the expected values
      expect(assetDataResult.get('id')).toBe(2);
      expect(assetDataResult.get('name')).toBe('test-asset');
      expect(assetData0Result.get('id')).toBe(20);
      expect(assetData0Result.get('name')).toBe('test-asset-0');
      expect(progressResult).toBe(false);
    });

    it('should handle all asset data selectors together', () => {
      const assetDataSelector = makeSelectUploadedAssetData();
      const assetData0Selector = makeSelectUploadedAssetData0();
      const assetData1Selector = makeSelectUploadedAssetData1();

      const assetDataResult = assetDataSelector(mockStateWithMobilePushNew);
      const assetData0Result = assetData0Selector(mockStateWithMobilePushNew);
      const assetData1Result = assetData1Selector(mockStateWithMobilePushNew);

      expect(assetDataResult.get('id')).toBe(1);
      expect(assetDataResult.get('url')).toBe('test-url');
      expect(assetData0Result.get('id')).toBe(10);
      expect(assetData0Result.get('url')).toBe('test-url-0');
      expect(assetData1Result.get('id')).toBe(11);
      expect(assetData1Result.get('url')).toBe('test-url-1');
    });
  });
});
