import {
  call, put, takeLatest,
} from 'redux-saga/effects';
import { createMockTask } from 'redux-saga/utils';
import { expectSaga } from 'redux-saga-test-plan';
import * as sagas from '../sagas';
import { v2InAppSagas } from '../sagas';
import * as Api from '../../../services/api';
import * as types from '../constants';
import { INAPP } from '../../CreativesContainer/constants';

describe('test for uploadInAppAsset function', () => {
  it('should dispatch UPLOAD_INAPP_ASSET_SUCCESS action with asset data, status code, and template type', () => {
    // Mock the necessary dependencies
    const params = {
      file: new File([""], "filename"),
      assetType: 'image',
      fileParams: {
        name: 'image.jpg',
        size: 1024,
      },
      mode: 'create',
      wechatParams: {
        source: 'wechat',
        appId: '123456',
        appSecret: 'abcdef',
      },
      whatsappParams: {
        source: 'whatsapp',
        wabaId: '987654',
        accessToken: 'xyz123',
        hostName: 'whatsapp.com',
      },
    };

    // Mock the API.uploadFile function
    const uploadFileMock = jest.spyOn(Api, 'uploadFile').mockImplementation(() => Promise.resolve({
      response: {
        asset: { id: 1, name: 'image.jpg' },
      },
      status: {
        code: 200,
      },
    }));

    const result = { response: { asset: { id: 1, name: 'image.jpg' } }, status: { code: 200 } };

    // Invoke the function
    const generator = sagas.uploadInAppAsset(params);
    generator.next();
    const actual = generator.next(result).value;

    // Assert the dispatched action
    expect(actual).toEqual(
      put({
        type: types.UPLOAD_INAPP_ASSET_SUCCESS,
        data: { id: 1, name: 'image.jpg' },
        statusCode: 200,
        templateType: params.templateType,
      })
    );

    // Restore the mocks
    uploadFileMock.mockRestore();
  });

  it('should dispatch UPLOAD_INAPP_ASSET_FAILURE action with error', () => {
    // Mock the necessary dependencies
    const params = {
      file: new File([""], "filename"),
      assetType: 'image',
      fileParams: {
        name: 'image.jpg',
        size: 1024,
      },
      mode: 'create',
      wechatParams: {
        source: 'wechat',
        appId: '123456',
        appSecret: 'abcdef',
      },
      whatsappParams: {
        source: 'whatsapp',
        wabaId: '987654',
        accessToken: 'xyz123',
        hostName: 'whatsapp.com',
      },
    };

    // Mock the API.uploadFile function
    const uploadFileMock = jest.spyOn(Api, 'uploadFile').mockImplementation(() => Promise.reject(new Error('Upload failed')));
    // Invoke the function
    const generator = sagas.uploadInAppAsset(params);
    generator.next();

    // Assert the dispatched action
    expect(generator.throw(new Error('Upload failed')).value).toEqual(
      put({ type: types.UPLOAD_INAPP_ASSET_FAILURE, error: new Error('Upload failed') })
    );

    // Restore the mocks
    uploadFileMock.mockRestore();
  });
  it('should call uploadInAppAsset when UPLOAD_INAPP_ASSET_REQUEST action is dispatched', () => {
    const watcher = sagas.watchUploadInAppAsset();
    const uploadInAppAssetGenerator = watcher.next().value;
    expect(uploadInAppAssetGenerator).toEqual(takeLatest(types.UPLOAD_INAPP_ASSET_REQUEST, sagas.uploadInAppAsset));
  });
  it('should cancel the watcher watchUploadInAppAsset', () => {
    const gen = sagas.watchUploadInAppAsset();
    const mockTask = createMockTask();

    // Advance the generator to the takeLatest effect
    expect(gen.next().value).toEqual(
      takeLatest(types.UPLOAD_INAPP_ASSET_REQUEST, sagas.uploadInAppAsset),
    );

    // Pass the mock task to the takeLatest effect
    expect(gen.next(mockTask).done).toBe(true);

    // Call the cancel function on the mock task to simulate cancellation
    expect(mockTask.isRunning()).toBe(true); // the task is running
    expect(gen.next().value).toEqual(undefined);
  });
});

describe('test for inAppTemplateCreate function', () => {
  it('should handle TEMPLATE_CREATE_SUCCESS', () => {
    const payload = {}; // Add your payload for testing
    const mockResult = {
      status: {
        code: 200,
      },
      response: { /* mock response */ },
    };

    const iterator = sagas.inAppTemplateCreate({ payload, callback: jest.fn() });

    // Test the yield call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload })
    expect(iterator.next().value).toEqual(call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload }));

    // Test the result
    expect(iterator.next(mockResult).value).toEqual(
      put({
        type: types.INAPP_TEMPLATE_CREATE_SUCCESS,
        data: mockResult.response,
        statusCode: mockResult.status.code,
        errorMsg: undefined, // No error message expected
      })
    );

    // Ensure the saga completes
    expect(iterator.next().done).toBe(true);
  });

  it('should handle error case', () => {
    const payload = {}; // Add your payload for testing
    const mockResult = {
      status: {
        code: 400,
      },
      // message: 'error',
      response: { /* mock response */ },
    };

    const iterator = sagas.inAppTemplateCreate({ payload, callback: jest.fn() });

    // Test the yield call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload })
    expect(iterator.next().value).toEqual(call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload }));

    // Test the result
    expect(iterator.next(mockResult).value).toEqual(
      put({
        type: types.INAPP_TEMPLATE_CREATE_FAILURE,
        error: 400,
        errorMsg: 400, // No error message expected
      })
    );

    // Ensure the saga completes
    expect(iterator.next().done).toBe(true);
  });

  it('should handle INAPP_TEMPLATE_CREATE_FAILURE', () => {
    const payload = {}; // Add your payload for testing
    const error = new Error('Test error');
    const iterator = sagas.inAppTemplateCreate({ payload });

    // Test the yield call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload })
    expect(iterator.next().value).toEqual(call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload }));

    // Test the error handling path
    expect(iterator.throw(error).value).toEqual(
      put({
        type: types.INAPP_TEMPLATE_CREATE_FAILURE,
        error,
        errorMsg: undefined, // No error message expected
      })
    );

    // Ensure the saga completes
    expect(iterator.next().done).toBe(true);
  });
  it('should call inAppTemplateCreate when INAPP_TEMPLATE_CREATE_REQUEST action is dispatched', () => {
    const watcher = sagas.watchCreateTemplate();
    const gen = watcher.next().value;
    expect(gen).toEqual(takeLatest(types.INAPP_TEMPLATE_CREATE_REQUEST, sagas.inAppTemplateCreate));
  });
  it('should cancel the watcher watchCreateTemplate', () => {
    const gen = sagas.watchCreateTemplate();
    const mockTask = createMockTask();

    // Advance the generator to the takeLatest effect
    expect(gen.next().value).toEqual(
      takeLatest(types.INAPP_TEMPLATE_CREATE_REQUEST, sagas.inAppTemplateCreate),
    );

    // Pass the mock task to the takeLatest effect
    expect(gen.next(mockTask).done).toBe(true);

    // Call the cancel function on the mock task to simulate cancellation
    expect(mockTask.isRunning()).toBe(true); // the task is running
    expect(gen.next().value).toEqual(undefined);
  });
});

describe('test for editTemplate function', () => {
  it('should handle INAPP_EDIT_TEMPLATE_SUCCESS', () => {
    const payload = {}; // Add your payload for testing
    const mockResult = {
      status: {
        code: 200,
      },
      response: { /* mock response */ },
    };

    const iterator = sagas.editTemplate({ payload, callback: jest.fn() });

    // Test the yield call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload })
    expect(iterator.next().value).toEqual(call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload }));

    // Test the result
    expect(iterator.next(mockResult).value).toEqual(
      put({
        type: types.INAPP_EDIT_TEMPLATE_SUCCESS,
        data: mockResult.response,
        statusCode: mockResult.status.code,
        errorMsg: undefined, // No error message expected
      })
    );

    // Ensure the saga completes
    expect(iterator.next().done).toBe(true);
  });

  it('should handle error case', () => {
    const payload = {}; // Add your payload for testing
    const mockResult = {
      status: {
        code: 400,
      },
      // message: 'error',
      response: { /* mock response */ },
    };

    const iterator = sagas.editTemplate({ payload, callback: jest.fn() });

    // Test the yield call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload })
    expect(iterator.next().value).toEqual(call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload }));

    // Test the result
    expect(iterator.next(mockResult).value).toEqual(
      put({
        type: types.INAPP_EDIT_TEMPLATE_FAILURE,
        error: 400,
        errorMsg: 400, // No error message expected
      })
    );

    // Ensure the saga completes
    expect(iterator.next().done).toBe(true);
  });

  it('should handle EDIT_TEMPLATE_FAILURE', () => {
    const payload = {}; // Add your payload for testing
    const error = new Error('Test error');
    const iterator = sagas.editTemplate({ payload });

    // Test the yield call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload })
    expect(iterator.next().value).toEqual(call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload }));

    // Test the error handling path
    expect(iterator.throw(error).value).toEqual(
      put({
        type: types.INAPP_EDIT_TEMPLATE_FAILURE,
        error,
        errorMsg: undefined, // No error message expected
      })
    );

    // Ensure the saga completes
    expect(iterator.next().done).toBe(true);
  });
  it('should call editTemplate when INAPP_EDIT_TEMPLATE_REQUEST action is dispatched', () => {
    const watcher = sagas.watchEditTemplate();
    const gen = watcher.next().value;
    expect(gen).toEqual(takeLatest(types.INAPP_EDIT_TEMPLATE_REQUEST, sagas.editTemplate));
  });
  it('should cancel the watcher watchCreateTemplate', () => {
    const gen = sagas.watchEditTemplate();
    const mockTask = createMockTask();

    // Advance the generator to the takeLatest effect
    expect(gen.next().value).toEqual(
      takeLatest(types.INAPP_EDIT_TEMPLATE_REQUEST, sagas.editTemplate),
    );

    // Pass the mock task to the takeLatest effect
    expect(gen.next(mockTask).done).toBe(true);

    // Call the cancel function on the mock task to simulate cancellation
    expect(mockTask.isRunning()).toBe(true); // the task is running
    expect(gen.next().value).toEqual(undefined);
  });
});

describe('test for getTemplateDetails', () => {
  it('should handle GET_INAPP_TEMPLATE_DETAILS_SUCCESS', () => {
    const payload = {}; // Add your payload for testing
    const mockResult = {
      status: {
        code: 200,
      },
      response: { /* mock response */ },
    };

    const iterator = sagas.getTemplateDetails({ payload, callback: jest.fn() });

    // Test the yield call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload })
    expect(iterator.next().value).toEqual(call(Api.getTemplateDetails, { channel: 'INAPP', id: undefined }));

    // Test the result
    expect(iterator.next(mockResult).value).toEqual(
      put({
        type: types.GET_INAPP_TEMPLATE_DETAILS_SUCCESS,
        data: mockResult.response,
      })
    );

    // Ensure the saga completes
    expect(iterator.next().done).toBe(true);
  });

  it('should handle GET_INAPP_TEMPLATE_DETAILS_FAILURE', () => {
    const payload = {}; // Add your payload for testing
    const error = new Error('Test error');
    const iterator = sagas.getTemplateDetails({ channel: INAPP, template: payload });

    // Test the yield call(Api.createChannelWiseTemplate, { channel: INAPP, template: payload })
    expect(iterator.next().value).toEqual(call(Api.getTemplateDetails, { channel: 'INAPP', id: undefined }));

    // Test the error handling path
    expect(iterator.throw(error).value).toEqual(
      put({
        type: types.GET_INAPP_TEMPLATE_DETAILS_FAILURE,
        error,
        errorMsg: undefined, // No error message expected
      })
    );

    // Ensure the saga completes
    expect(iterator.next().done).toBe(true);
  });
  it('should call getTemplateDetails when GET_INAPP_TEMPLATE_DETAILS_REQUEST action is dispatched', () => {
    const watcher = sagas.watchGetTemplateDetails();
    const gen = watcher.next().value;

    expect(gen).toEqual(takeLatest(types.GET_INAPP_TEMPLATE_DETAILS_REQUEST, sagas.getTemplateDetails));
  });
  it('should cancel the watcher watchGetTemplateDetails', () => {
    const gen = sagas.watchGetTemplateDetails();
    const mockTask = createMockTask();

    // Advance the generator to the takeLatest effect
    expect(gen.next().value).toEqual(
      takeLatest(types.GET_INAPP_TEMPLATE_DETAILS_REQUEST, sagas.getTemplateDetails),
    );

    // Pass the mock task to the takeLatest effect
    expect(gen.next(mockTask).done).toBe(true);

    // Call the cancel function on the mock task to simulate cancellation
    expect(mockTask.isRunning()).toBe(true); // the task is running
    expect(gen.next().value).toEqual(undefined);
  });
});

describe('test for getBeePopupBuilderToken', () => {
  it('should call getBeePopupBuilderToken when GET_BEE_POPUP_BUILDER_TOKEN_REQUEST action is dispatched', () => {
    const watcher = sagas.watchGetBeePopupBuilderToken();
    const gen = watcher.next().value;
    expect(gen).toEqual(takeLatest(types.GET_BEE_POPUP_BUILDER_TOKEN_REQUEST, sagas.getBeePopupBuilderToken));
  });
  it('should cancel the watcher watchGetBeePopupBuilderToken', () => {
    const gen = sagas.watchGetBeePopupBuilderToken();
    const mockTask = createMockTask();
    expect(gen.next().value).toEqual(takeLatest(types.GET_BEE_POPUP_BUILDER_TOKEN_REQUEST, sagas.getBeePopupBuilderToken));
    expect(gen.next(mockTask).done).toBe(true);
    expect(mockTask.isRunning()).toBe(true);
    expect(gen.next().value).toEqual(undefined);
  });
  it('should handle GET_BEE_POPUP_BUILDER_TOKEN_SUCCESS', () => {
    const payload = {}; // Add your payload for testing
    const mockResult = {
      success: true,
      status: {
        code: 200,
      },
      response: { /* mock response */ },
    };
    const iterator = sagas.getBeePopupBuilderToken({ payload, callback: jest.fn() });
    expect(iterator.next().value).toEqual(call(Api.getBeePopupBuilderToken));
    expect(iterator.next(mockResult).value).toEqual(
      put({ type: types.GET_BEE_POPUP_BUILDER_TOKEN_SUCCESS, data: mockResult.response })
    );
    expect(iterator.next().done).toBe(true);
  });
  it('should handle GET_BEE_POPUP_BUILDER_TOKEN_FAILURE', () => {
    const payload = {};
    const error = new Error('Test error');
    const iterator = sagas.getBeePopupBuilderToken({ payload });
    expect(iterator.next().value).toEqual(call(Api.getBeePopupBuilderToken));
    expect(iterator.throw(error).value).toEqual(
      put({ type: types.GET_BEE_POPUP_BUILDER_TOKEN_FAILURE, error })
    );
    expect(iterator.next().done).toBe(true);
  });
  it('should handle error case', () => {
    const payload = {};
    const mockResult = {
      success: false,
      status: {
        code: 400,
      },
      message: 'Test error',
    };
    const iterator = sagas.getBeePopupBuilderToken({ payload });
    expect(iterator.next().value).toEqual(call(Api.getBeePopupBuilderToken));
    expect(iterator.next(mockResult).value).toEqual(
      put({ type: types.GET_BEE_POPUP_BUILDER_TOKEN_FAILURE, error: mockResult.message })
    );
    expect(iterator.next().done).toBe(true);
  });
});


describe("v2InAppSagas Combined", () => {
  it("should initialize all v2InAppSagas-related watcher sagas without error", () => expectSaga(v2InAppSagas).run());
});
