import { fromJS } from 'immutable';
import {
  createAsyncAssetUploadConstants,
  createAsyncAssetUploadReducerCases,
  createPollingConfig,
} from '../asyncAssetUpload';

describe('asyncAssetUpload utilities', () => {
  describe('createAsyncAssetUploadConstants', () => {
    it('should create constants for a given channel prefix', () => {
      const constants = createAsyncAssetUploadConstants('WHATSAPP', 'app/v2Containers/Whatsapp');
      
      expect(constants).toEqual({
        UPLOAD_WHATSAPP_ASSET_PROCESSING: 'app/v2Containers/Whatsapp/UPLOAD_WHATSAPP_ASSET_PROCESSING',
        UPLOAD_WHATSAPP_ASSET_COMPLETED: 'app/v2Containers/Whatsapp/UPLOAD_WHATSAPP_ASSET_COMPLETED',
        UPLOAD_WHATSAPP_ASSET_FAILED: 'app/v2Containers/Whatsapp/UPLOAD_WHATSAPP_ASSET_FAILED',
        UPLOAD_WHATSAPP_ASSET_TIMEOUT: 'app/v2Containers/Whatsapp/UPLOAD_WHATSAPP_ASSET_TIMEOUT',
      });
    });

    it('should use default container path when not provided', () => {
      const constants = createAsyncAssetUploadConstants('MOBILEPUSH');
      
      expect(constants.UPLOAD_MOBILEPUSH_ASSET_PROCESSING).toBe(
        'app/v2Containers/MOBILEPUSH/UPLOAD_MOBILEPUSH_ASSET_PROCESSING'
      );
    });

    it('should handle lowercase channel prefix', () => {
      const constants = createAsyncAssetUploadConstants('email', 'app/v2Containers/Email');
      
      expect(constants.UPLOAD_EMAIL_ASSET_PROCESSING).toBe(
        'app/v2Containers/Email/UPLOAD_EMAIL_ASSET_PROCESSING'
      );
    });

    it('should create constants for different channels', () => {
      const smsConstants = createAsyncAssetUploadConstants('SMS', 'app/v2Containers/Sms');
      
      expect(smsConstants.UPLOAD_SMS_ASSET_PROCESSING).toContain('SMS');
      expect(smsConstants.UPLOAD_SMS_ASSET_COMPLETED).toContain('SMS');
      expect(smsConstants.UPLOAD_SMS_ASSET_FAILED).toContain('SMS');
      expect(smsConstants.UPLOAD_SMS_ASSET_TIMEOUT).toContain('SMS');
    });
  });

  describe('createAsyncAssetUploadReducerCases', () => {
    const mockActionTypes = {
      PROCESSING: 'TEST_PROCESSING',
      COMPLETED: 'TEST_COMPLETED',
      FAILED: 'TEST_FAILED',
      TIMEOUT: 'TEST_TIMEOUT',
    };

    const createInitialState = () => fromJS({
      uploadedAssetData: {},
      assetUploading: false,
      uploadAssetSuccess: false,
      assetProcessing: {},
    });

    it('should create reducer cases with default options', () => {
      const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
      
      expect(reducerCases.PROCESSING).toBe('TEST_PROCESSING');
      expect(reducerCases.COMPLETED).toBe('TEST_COMPLETED');
      expect(reducerCases.FAILED).toBe('TEST_FAILED');
      expect(reducerCases.TIMEOUT).toBe('TEST_TIMEOUT');
      expect(typeof reducerCases.handleProcessing).toBe('function');
      expect(typeof reducerCases.handleCompleted).toBe('function');
      expect(typeof reducerCases.handleFailed).toBe('function');
      expect(typeof reducerCases.handleTimeout).toBe('function');
    });

    describe('handleProcessing', () => {
      it('should set processing state correctly', () => {
        const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
        const state = createInitialState();
        const action = {
          payload: {
            assetId: 'asset-123',
            asset: { _id: 'asset-123', url: 'https://example.com/image.jpg' },
          },
        };
        
        const newState = reducerCases.handleProcessing(state, action);
        
        expect(newState.get('uploadAssetSuccess')).toBe(false);
        expect(newState.get('assetUploading')).toBe(true);
        expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('processing');
        expect(newState.getIn(['assetProcessing', 'asset-123', 'asset'])).toBeDefined();
        expect(newState.getIn(['assetProcessing', 'asset-123', 'startTime'])).toBeDefined();
      });
    });

    describe('handleCompleted', () => {
      it('should set completed state correctly without templateType', () => {
        const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
        const state = createInitialState();
        const action = {
          payload: {
            assetId: 'asset-123',
            asset: { _id: 'asset-123', url: 'https://example.com/image.jpg' },
          },
        };
        
        const newState = reducerCases.handleCompleted(state, action);
        
        expect(newState.get('uploadAssetSuccess')).toBe(true);
        expect(newState.get('assetUploading')).toBe(false);
        expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('completed');
        expect(newState.get('uploadedAssetData')).toEqual(fromJS(action.payload.asset));
      });

      it('should set completed state correctly with templateType', () => {
        const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
        const state = createInitialState();
        const action = {
          templateType: 0,
          payload: {
            assetId: 'asset-123',
            asset: { _id: 'asset-123', url: 'https://example.com/image.jpg' },
          },
        };
        
        const newState = reducerCases.handleCompleted(state, action);
        
        expect(newState.get('uploadAssetSuccess')).toBe(true);
        expect(newState.get('assetUploading')).toBe(false);
        expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('completed');
        expect(newState.get('uploadedAssetData0')).toEqual(fromJS(action.payload.asset));
      });
    });

    describe('handleFailed', () => {
      it('should set failed state correctly', () => {
        const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
        const state = createInitialState();
        const action = {
          payload: {
            assetId: 'asset-123',
            error: 'Processing failed',
          },
        };
        
        const newState = reducerCases.handleFailed(state, action);
        
        expect(newState.get('uploadAssetSuccess')).toBe(false);
        expect(newState.get('assetUploading')).toBe(false);
        expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('failed');
        expect(newState.getIn(['assetProcessing', 'asset-123', 'error'])).toBe('Processing failed');
      });
    });

    describe('handleTimeout', () => {
      it('should set timeout state correctly', () => {
        const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes);
        const state = createInitialState();
        const action = {
          payload: {
            assetId: 'asset-123',
            message: 'Processing timeout',
          },
        };
        
        const newState = reducerCases.handleTimeout(state, action);
        
        expect(newState.get('uploadAssetSuccess')).toBe(false);
        expect(newState.get('assetUploading')).toBe(false);
        expect(newState.getIn(['assetProcessing', 'asset-123', 'status'])).toBe('timeout');
        expect(newState.getIn(['assetProcessing', 'asset-123', 'error'])).toBe('Processing timeout');
      });
    });

    it('should use custom state keys when provided', () => {
      const reducerCases = createAsyncAssetUploadReducerCases(mockActionTypes, {
        uploadedAssetDataKey: 'customAssetData',
        assetUploadingKey: 'customUploading',
        uploadAssetSuccessKey: 'customSuccess',
        assetProcessingKey: 'customProcessing',
      });
      
      const state = fromJS({
        customAssetData: {},
        customUploading: false,
        customSuccess: false,
        customProcessing: {},
      });
      
      const action = {
        payload: {
          assetId: 'asset-123',
          asset: { _id: 'asset-123' },
        },
      };
      
      const newState = reducerCases.handleProcessing(state, action);
      
      expect(newState.get('customSuccess')).toBe(false);
      expect(newState.get('customUploading')).toBe(true);
      expect(newState.getIn(['customProcessing', 'asset-123'])).toBeDefined();
    });
  });

  describe('createPollingConfig', () => {
    const mockActionTypes = {
      COMPLETED: 'TEST_COMPLETED',
      FAILED: 'TEST_FAILED',
      TIMEOUT: 'TEST_TIMEOUT',
    };

    it('should create polling config correctly', () => {
      const config = createPollingConfig('image', 'asset-123', mockActionTypes, 0);
      
      expect(config).toEqual({
        type: 'image',
        assetId: 'asset-123',
        onCompleted: expect.any(Function),
        onFailed: expect.any(Function),
        onTimeout: expect.any(Function),
      });
    });

    it('should create onCompleted action creator', () => {
      const config = createPollingConfig('image', 'asset-123', mockActionTypes, 0);
      const data = {
        assetId: 'asset-123',
        asset: { _id: 'asset-123' },
        duration: 1000,
      };
      
      const action = config.onCompleted(data);
      
      expect(action).toEqual({
        type: 'TEST_COMPLETED',
        payload: data,
        templateType: 0,
      });
    });

    it('should create onFailed action creator', () => {
      const config = createPollingConfig('image', 'asset-123', mockActionTypes, 0);
      const data = {
        assetId: 'asset-123',
        error: 'Processing failed',
        duration: 1000,
      };
      
      const action = config.onFailed(data);
      
      expect(action).toEqual({
        type: 'TEST_FAILED',
        payload: data,
        templateType: 0,
      });
    });

    it('should create onTimeout action creator', () => {
      const config = createPollingConfig('image', 'asset-123', mockActionTypes, 0);
      const data = {
        assetId: 'asset-123',
        message: 'Timeout',
        duration: 90000,
      };
      
      const action = config.onTimeout(data);
      
      expect(action).toEqual({
        type: 'TEST_TIMEOUT',
        payload: data,
        templateType: 0,
      });
    });

    it('should handle undefined templateType', () => {
      const config = createPollingConfig('image', 'asset-123', mockActionTypes);
      const data = { assetId: 'asset-123', asset: {} };
      
      const action = config.onCompleted(data);
      
      expect(action.templateType).toBeUndefined();
    });

    it('should work with different asset types', () => {
      const videoConfig = createPollingConfig('video', 'asset-456', mockActionTypes, 1);
      
      expect(videoConfig.type).toBe('video');
      expect(videoConfig.assetId).toBe('asset-456');
      expect(videoConfig.onCompleted({}).templateType).toBe(1);
    });
  });
});
