import { fromJS } from 'immutable';
import viberReducer from '../reducer';
import * as types from '../constants';
import { ASSET_STATUS } from '../../../utils/assetStatusConstants';

const initialState = fromJS({
  uploadedAssetData: {},
  createTemplateInProgress: false,
  assetProcessing: {},
});

describe('viberReducer', () => {
  it('returns initial state for unknown action', () => {
    expect(viberReducer(undefined, { type: '@@INIT' })).toEqual(initialState);
  });

  describe('CREATE_VIBER_TEMPLATE_*', () => {
    it('handles CREATE_VIBER_TEMPLATE_REQUEST', () => {
      const next = viberReducer(initialState, {
        type: types.CREATE_VIBER_TEMPLATE_REQUEST,
      });
      expect(next.get('createTemplateInProgress')).toBe(true);
      expect(next.get('createTemplateError')).toBe(false);
      expect(next.get('createTemplateErrorMessage')).toEqual(fromJS(''));
    });

    it('handles CREATE_VIBER_TEMPLATE_SUCCESS with status > 300', () => {
      const next = viberReducer(initialState, {
        type: types.CREATE_VIBER_TEMPLATE_SUCCESS,
        data: { id: 'x' },
        statusCode: 400,
        errorMsg: 'oops',
      });
      expect(next.get('createTemplateInProgress')).toBe(false);
      expect(next.get('response')).toEqual({ id: 'x' });
      expect(next.get('createTemplateError')).toBe(true);
      expect(next.get('createTemplateErrorMessage')).toEqual(fromJS('oops'));
    });

    it('handles CREATE_VIBER_TEMPLATE_SUCCESS with status <= 300', () => {
      const next = viberReducer(initialState, {
        type: types.CREATE_VIBER_TEMPLATE_SUCCESS,
        data: { id: 'x' },
        statusCode: 200,
        errorMsg: '',
      });
      expect(next.get('createTemplateError')).toBe(false);
    });

    it('handles CREATE_VIBER_TEMPLATE_FAILURE', () => {
      const next = viberReducer(initialState, {
        type: types.CREATE_VIBER_TEMPLATE_FAILURE,
        errorMsg: 'bad',
      });
      expect(next.get('createTemplateInProgress')).toBe(false);
      expect(next.get('createTemplateError')).toBe(true);
      expect(next.get('createTemplateErrorMessage')).toEqual(fromJS('bad'));
    });
  });

  describe('UPLOAD_VIBER_ASSET_*', () => {
    it('handles UPLOAD_VIBER_ASSET_REQUEST', () => {
      const next = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_REQUEST,
      });
      expect(next.get('uploadAssetSuccess')).toBe(false);
      expect(next.get('assetUploading')).toBe(true);
    });

    it('handles UPLOAD_VIBER_ASSET_SUCCESS and wraps data with fromJS (finding 2)', () => {
      const payload = { url: 'https://cdn/x.png', meta: { size: 100 } };
      const next = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_SUCCESS,
        data: payload,
        statusCode: 200,
      });
      expect(next.get('assetUploading')).toBe(false);
      expect(next.get('uploadAssetSuccess')).toBe(true);
      // must be wrapped in Immutable (same as asyncUploadCases.handleCompleted)
      const stored = next.get('uploadedAssetData');
      expect(stored).toEqual(fromJS(payload));
      // verify it's actually an Immutable Map, not a plain JS object
      expect(stored.toJS).toBeDefined();
      expect(typeof stored.toJS).toBe('function');
      expect(stored.get('url')).toBe(payload.url);
    });

    it('handles UPLOAD_VIBER_ASSET_SUCCESS with templateType key wrapped in fromJS', () => {
      const payload = { url: 'https://cdn/y.mp4' };
      const next = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_SUCCESS,
        data: payload,
        statusCode: 200,
        templateType: 3,
      });
      const stored = next.get('uploadedAssetData3');
      expect(stored).toEqual(fromJS(payload));
      expect(stored.get('url')).toBe(payload.url);
    });

    it('UPLOAD_VIBER_ASSET_SUCCESS sets uploadAssetSuccess false when status >= 300', () => {
      const next = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_SUCCESS,
        data: {},
        statusCode: 500,
      });
      expect(next.get('uploadAssetSuccess')).toBe(false);
    });

    it('UPLOAD_VIBER_ASSET_SUCCESS sync and async produce same shape', () => {
      const asset = { url: 'https://cdn/same.png' };
      const sync = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_SUCCESS,
        data: asset,
        statusCode: 200,
      });
      const async_ = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_COMPLETED,
        payload: { assetId: 'a1', asset },
      });
      // Both paths should store uploadedAssetData as Immutable fromJS(asset)
      expect(sync.get('uploadedAssetData')).toEqual(async_.get('uploadedAssetData'));
    });

    it('handles UPLOAD_VIBER_ASSET_FAILURE', () => {
      const next = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_FAILURE,
      });
      expect(next.get('uploadAssetSuccess')).toBe(false);
      expect(next.get('assetUploading')).toBe(false);
    });
  });

  describe('async polling cases', () => {
    it('handles UPLOAD_VIBER_ASSET_PROCESSING', () => {
      const next = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_PROCESSING,
        payload: { assetId: 'a1', asset: { id: 'a1' } },
      });
      expect(next.get('assetUploading')).toBe(true);
      expect(next.get('uploadAssetSuccess')).toBe(false);
      expect(next.getIn(['assetProcessing', 'a1', 'status'])).toBe(ASSET_STATUS.PROCESSING);
    });

    it('handles UPLOAD_VIBER_ASSET_COMPLETED', () => {
      const next = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_COMPLETED,
        payload: { assetId: 'a1', asset: { url: 'https://cdn/x.png' } },
      });
      expect(next.get('assetUploading')).toBe(false);
      expect(next.get('uploadAssetSuccess')).toBe(true);
      expect(next.getIn(['assetProcessing', 'a1', 'status'])).toBe(ASSET_STATUS.COMPLETED);
      expect(next.get('uploadedAssetData')).toEqual(fromJS({ url: 'https://cdn/x.png' }));
    });

    it('handles UPLOAD_VIBER_ASSET_FAILED', () => {
      const next = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_FAILED,
        payload: { assetId: 'a1', error: 'boom' },
      });
      expect(next.get('assetUploading')).toBe(false);
      expect(next.get('uploadAssetSuccess')).toBe(false);
      expect(next.getIn(['assetProcessing', 'a1', 'status'])).toBe(ASSET_STATUS.FAILED);
      expect(next.getIn(['assetProcessing', 'a1', 'error'])).toBe('boom');
    });

    it('handles UPLOAD_VIBER_ASSET_TIMEOUT', () => {
      const next = viberReducer(initialState, {
        type: types.UPLOAD_VIBER_ASSET_TIMEOUT,
        payload: { assetId: 'a1', message: 'timed out' },
      });
      expect(next.get('assetUploading')).toBe(false);
      expect(next.getIn(['assetProcessing', 'a1', 'status'])).toBe(ASSET_STATUS.TIMEOUT);
      expect(next.getIn(['assetProcessing', 'a1', 'error'])).toBe('timed out');
    });
  });

  describe('CLEAR_VIBER_ASSET (finding 3)', () => {
    const dirtyState = initialState
      .set('assetUploading', true)
      .set('uploadAssetSuccess', true)
      .set('uploadedAssetData', fromJS({ url: 'x' }))
      .set('uploadedAssetData2', fromJS({ url: 'y' }))
      .setIn(['assetProcessing', 'a1'], fromJS({ status: 'processing' }));

    it('clears default uploadedAssetData and resets upload flags', () => {
      const next = viberReducer(dirtyState, { type: types.CLEAR_VIBER_ASSET });
      expect(next.has('uploadedAssetData')).toBe(false);
      expect(next.get('assetProcessing')).toEqual(fromJS({}));
      expect(next.get('assetUploading')).toBe(false);
      expect(next.get('uploadAssetSuccess')).toBe(false);
    });

    it('clears templateType-specific uploadedAssetData and resets upload flags', () => {
      const next = viberReducer(dirtyState, {
        type: types.CLEAR_VIBER_ASSET,
        templateType: 2,
      });
      expect(next.has('uploadedAssetData2')).toBe(false);
      // default key untouched by specific clear
      expect(next.has('uploadedAssetData')).toBe(true);
      expect(next.get('assetProcessing')).toEqual(fromJS({}));
      expect(next.get('assetUploading')).toBe(false);
      expect(next.get('uploadAssetSuccess')).toBe(false);
    });
  });

  describe('CLEAR_VIBER_DATA (finding 3 mirror)', () => {
    it('clears assetProcessing, assetUploading, uploadAssetSuccess', () => {
      const dirtyState = initialState
        .set('assetUploading', true)
        .set('uploadAssetSuccess', true)
        .set('metaEntities', fromJS({ some: 'data' }))
        .set('templateDetails', fromJS({ id: 'x' }))
        .setIn(['assetProcessing', 'a1'], fromJS({ status: 'processing' }));
      const next = viberReducer(dirtyState, { type: types.CLEAR_VIBER_DATA });
      expect(next.has('uploadedAssetData')).toBe(false);
      expect(next.has('metaEntities')).toBe(false);
      expect(next.has('templateDetails')).toBe(false);
      expect(next.get('assetProcessing')).toEqual(fromJS({}));
      expect(next.get('assetUploading')).toBe(false);
      expect(next.get('uploadAssetSuccess')).toBe(false);
    });
  });

  describe('EDIT_VIBER_TEMPLATE_*', () => {
    it('handles EDIT_VIBER_TEMPLATE_REQUEST', () => {
      const next = viberReducer(initialState, {
        type: types.EDIT_VIBER_TEMPLATE_REQUEST,
      });
      expect(next.get('editTemplateInProgress')).toBe(true);
      expect(next.get('editTemplateError')).toBe(false);
    });

    it('handles EDIT_VIBER_TEMPLATE_SUCCESS', () => {
      const next = viberReducer(initialState, {
        type: types.EDIT_VIBER_TEMPLATE_SUCCESS,
        data: { id: 'e' },
        statusCode: 200,
        errorMsg: '',
      });
      expect(next.get('editTemplateInProgress')).toBe(false);
      expect(next.get('editResponse')).toEqual({ id: 'e' });
      expect(next.get('editTemplateError')).toBe(false);
    });

    it('handles EDIT_VIBER_TEMPLATE_SUCCESS error status', () => {
      const next = viberReducer(initialState, {
        type: types.EDIT_VIBER_TEMPLATE_SUCCESS,
        data: {},
        statusCode: 500,
        errorMsg: 'err',
      });
      expect(next.get('editTemplateError')).toBe(true);
    });

    it('handles EDIT_VIBER_TEMPLATE_FAILURE', () => {
      const next = viberReducer(initialState, {
        type: types.EDIT_VIBER_TEMPLATE_FAILURE,
        errorMsg: 'nope',
      });
      expect(next.get('editTemplateError')).toBe(true);
    });
  });

  describe('GET/CLEAR branches', () => {
    it('handles GET_VIBER_TEMPLATE_DETAILS_REQUEST', () => {
      const next = viberReducer(initialState, {
        type: types.GET_VIBER_TEMPLATE_DETAILS_REQUEST,
      });
      expect(next.get('getTemplateDetailsInProgress')).toBe(true);
    });

    it('handles GET_VIBER_TEMPLATE_DETAILS_SUCCESS', () => {
      const next = viberReducer(initialState, {
        type: types.GET_VIBER_TEMPLATE_DETAILS_SUCCESS,
        data: { id: 'd' },
      });
      expect(next.get('getTemplateDetailsInProgress')).toBe(false);
      expect(next.get('templateDetails')).toEqual({ id: 'd' });
    });

    it('handles GET_VIBER_TEMPLATE_DETAILS_FAILURE / CLEAR_VIBER_EDIT_RESPONSE_REQUEST', () => {
      const next = viberReducer(initialState, {
        type: types.CLEAR_VIBER_EDIT_RESPONSE_REQUEST,
      });
      expect(next.get('editResponse')).toEqual({});
    });

    it('handles CLEAR_VIBER_CREATE_RESPONSE_REQUEST', () => {
      const next = viberReducer(initialState, {
        type: types.CLEAR_VIBER_CREATE_RESPONSE_REQUEST,
      });
      expect(next.get('response')).toEqual({});
    });
  });
});
