import reducer, { initialState } from "../reducer";
import * as types from "../constants";
import * as mockData from "./mockData";
import { RCS } from "../../CreativesContainer/constants";

describe("test reducer", () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  it.concurrent("should return the initial state", () => {
    expect(reducer(undefined, {})).toEqual(initialState);
  });

  it.concurrent("should handle GET_ALL_TEMPLATES_REQUEST", () => {
    const action = {
      type: types.GET_ALL_TEMPLATES_REQUEST,
    };
    expect(reducer(initialState, action).toJS()).toEqual({
      ...initialState.toJS(),
      getAllTemplatesInProgress: true,
    });
  });

  it.concurrent("should handle GET_ALL_TEMPLATES_SUCCESS", () => {
    const action = {
      type: types.GET_ALL_TEMPLATES_SUCCESS,
      data: mockData.getAllTemplatesListSuccess,
    };
    const expectedResult = {
      ...initialState.toJS(),
      getAllTemplatesInProgress: false,
      templateError: {},
      weCRMtemplates: [],
      templates: [undefined],
      isSearch: undefined,
    };
    expect(reducer(initialState, action).toJS()).toEqual(expectedResult);
  });

  it.concurrent("should handle GET_ALL_TEMPLATES_FAILURE", () => {
    const action = {
      type: types.GET_ALL_TEMPLATES_FAILURE,
    };
    expect(reducer(initialState, action).toJS()).toEqual({
      ...initialState.toJS(),
      getAllTemplatesInProgress: false,
      templateError: undefined,
    });
  });
});


describe("test reducer - sender details", () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  it.concurrent("should handle GET_SENDER_DETAILS_REQUEST", () => {
    const action = { type: types.GET_SENDER_DETAILS_REQUEST };
    expect(reducer(initialState, action).toJS()).toEqual({
      ...initialState.toJS(),
      senderDetails: { status: "REQUEST" },
    });
  });

  it.concurrent("should handle GET_SENDER_DETAILS_SUCCESS for WHATSAPP (multi-account channel)", () => {
    const action = {
      type: types.GET_SENDER_DETAILS_SUCCESS,
      payload: mockData.senderDetailsWhatsapp,
    };
    expect(reducer(initialState, action).toJS()).toEqual({
      ...initialState.toJS(),
      senderDetails: {
        status: "SUCCESS",
        domainProperties: mockData.senderDetailsWhatsapp.domainProperties,
        errors: [],
      },
    });
  });

  it.concurrent("should handle GET_SENDER_DETAILS_SUCCESS for non-multi-account channel", () => {
    const action = {
      type: types.GET_SENDER_DETAILS_SUCCESS,
      payload: mockData.senderDetailsSMS.hostName,
    };
    expect(reducer(initialState, action).toJS()).toEqual({
      ...initialState.toJS(),
      senderDetails: {
        status: "SUCCESS",
        hostName: mockData.senderDetailsSMS.hostName,
        errors: [],
      },
    });
  });

  it.concurrent("should handle GET_SENDER_DETAILS_FAILURE", () => {
    const action = {
      type: types.GET_SENDER_DETAILS_FAILURE,
      payload: mockData.errorMessage,
    };
    expect(reducer(initialState, action).toJS()).toEqual({
      ...initialState.toJS(),
      senderDetails: {
        status: "FAILURE",
        hostName: "",
        errors: mockData.errorMessage,
      },
    });
  });
});


describe("test reducer - delete template operations", () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  describe("DELETE_TEMPLATE actions", () => {
    it.concurrent("should handle DELETE_TEMPLATE_REQUEST", () => {
      const action = {
        type: types.DELETE_TEMPLATE_REQUEST,
      };
      expect(reducer(initialState, action).toJS()).toEqual({
        ...initialState.toJS(),
        deleteTemplateInProgress: true,
        deleteTemplateError: null,
      });
    });

    it.concurrent("should handle DELETE_TEMPLATE_SUCCESS", () => {
      const mockDeleteResponse = { message: "Template deleted successfully" };
      const action = {
        type: types.DELETE_TEMPLATE_SUCCESS,
        data: mockDeleteResponse,
      };
      expect(reducer(initialState, action).toJS()).toEqual({
        ...initialState.toJS(),
        deleteTemplateInProgress: false,
        deleteResponse: mockDeleteResponse,
        deleteTemplateError: null,
      });
    });

    it.concurrent("should handle DELETE_TEMPLATE_FAILURE", () => {
      const mockError = "Failed to delete template";
      const action = {
        type: types.DELETE_TEMPLATE_FAILURE,
        error: mockError,
      };
      expect(reducer(initialState, action).toJS()).toEqual({
        ...initialState.toJS(),
        deleteTemplateInProgress: false,
        deleteTemplateError: mockError,
      });
    });
  });

  describe("DELETE_RCS_TEMPLATE actions", () => {
    it.concurrent("should handle DELETE_RCS_TEMPLATE_REQUEST", () => {
      const action = {
        type: types.DELETE_RCS_TEMPLATE_REQUEST,
      };
      expect(reducer(initialState, action).toJS()).toEqual({
        ...initialState.toJS(),
        deleteRcsTemplateInProgress: true,
        deleteRcsTemplateError: null,
      });
    });

    it.concurrent("should handle DELETE_RCS_TEMPLATE_SUCCESS", () => {
      const mockRcsDeleteResponse = { message: "RCS Template deleted successfully" };
      const action = {
        type: types.DELETE_RCS_TEMPLATE_SUCCESS,
        data: mockRcsDeleteResponse,
      };
      expect(reducer(initialState, action).toJS()).toEqual({
        ...initialState.toJS(),
        deleteRcsTemplateInProgress: false,
        deleteRcsResponse: mockRcsDeleteResponse,
        deleteRcsTemplateError: null,
      });
    });

    it.concurrent("should handle DELETE_RCS_TEMPLATE_FAILURE", () => {
      const mockRcsError = "Failed to delete RCS template";
      const action = {
        type: types.DELETE_RCS_TEMPLATE_FAILURE,
        error: mockRcsError,
      };
      expect(reducer(initialState, action).toJS()).toEqual({
        ...initialState.toJS(),
        deleteRcsTemplateInProgress: false,
        deleteRcsTemplateError: mockRcsError,
      });
    });
  });

  describe("initial state verification for delete properties", () => {
    it.concurrent("should have correct initial values for delete properties", () => {
      const state = reducer(undefined, {});
      expect(state.toJS()).toEqual(
        expect.objectContaining({
          deleteTemplateError: null,
          deleteRcsTemplateInProgress: false,
          deleteRcsTemplateError: null,
          deleteRcsResponse: {},
        })
      );
    });
  });
});

describe("test reducer - SET account actions clear templates", () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  it.concurrent("should clear templates when SET_WECHAT_ACCOUNT is dispatched", () => {
    const stateWithTemplates = initialState.set('templates', [{ id: 1, name: "Template 1" }, { id: 2, name: "Template 2" }]);
    const mockAccount = { id: 1, name: "WeChat Account", sourceAccountIdentifier: "wechat123" };
    const action = {
      type: types.SET_WECHAT_ACCOUNT,
      weChatAccount: mockAccount,
    };
    const result = reducer(stateWithTemplates, action).toJS();
    expect(result.selectedWeChatAccount).toEqual(mockAccount);
    expect(result.templates).toEqual([]);
  });

  it.concurrent("should clear templates when SET_LINE_ACCOUNT is dispatched", () => {
    const stateWithTemplates = initialState.set('templates', [{ id: 1, name: "Template 1" }]);
    const mockAccount = { id: 1, name: "Line Account", sourceAccountIdentifier: "line123" };
    const action = {
      type: types.SET_LINE_ACCOUNT,
      account: mockAccount,
    };
    const result = reducer(stateWithTemplates, action).toJS();
    expect(result.selectedLineAccount).toEqual(mockAccount);
    expect(result.templates).toEqual([]);
  });

  it.concurrent("should clear templates when SET_VIBER_ACCOUNT is dispatched", () => {
    const stateWithTemplates = initialState.set('templates', [{ id: 1, name: "Template 1" }]);
    const mockAccount = { id: 1, name: "Viber Account", sourceAccountIdentifier: "viber123" };
    const action = {
      type: types.SET_VIBER_ACCOUNT,
      viberAccount: mockAccount,
    };
    const result = reducer(stateWithTemplates, action).toJS();
    expect(result.selectedViberAccount).toEqual(mockAccount);
    expect(result.templates).toEqual([]);
  });

  it.concurrent("should clear templates when SET_WHATSAPP_ACCOUNT is dispatched", () => {
    const stateWithTemplates = initialState.set('templates', [{ id: 1, name: "Template 1" }]);
    const mockAccount = { id: 1, name: "WhatsApp Account", sourceAccountIdentifier: "whatsapp123" };
    const action = {
      type: types.SET_WHATSAPP_ACCOUNT,
      account: mockAccount,
    };
    const result = reducer(stateWithTemplates, action).toJS();
    expect(result.selectedWhatsappAccount).toEqual(mockAccount);
    expect(result.templates).toEqual([]);
  });

  it.concurrent("should clear templates when SET_ZALO_ACCOUNT is dispatched", () => {
    const stateWithTemplates = initialState.set('templates', [{ id: 1, name: "Template 1" }]);
    const mockAccount = { id: 1, name: "Zalo Account", sourceAccountIdentifier: "zalo123" };
    const action = {
      type: types.SET_ZALO_ACCOUNT,
      account: mockAccount,
    };
    const result = reducer(stateWithTemplates, action).toJS();
    expect(result.selectedZaloAccount).toEqual(mockAccount);
    expect(result.templates).toEqual([]);
  });

  it.concurrent("should clear templates when SET_RCS_ACCOUNT is dispatched", () => {
    const stateWithTemplates = initialState.set('templates', [{ id: 1, name: "Template 1" }]);
    const mockAccount = { 
      id: 1, 
      name: "RCS Account", 
      sourceAccountIdentifier: "capillary_rcs",
      configs: { accessToken: "YugrOlhdSPpM" },
      hostName: "rcsicsbulk"
    };
    const action = {
      type: types.SET_RCS_ACCOUNT,
      account: mockAccount,
    };
    const result = reducer(stateWithTemplates, action).toJS();
    expect(result.selectedRcsAccount).toEqual(mockAccount);
    expect(result.templates).toEqual([]);
  });

  it.concurrent("should clear templates when SET_FACEBOOK_ACCOUNT is dispatched", () => {
    const stateWithTemplates = initialState.set('templates', [{ id: 1, name: "Template 1" }]);
    const mockAccount = { id: 1, name: "Facebook Account", accountName: "fb123" };
    const action = {
      type: types.SET_FACEBOOK_ACCOUNT,
      faceBookAccount: mockAccount,
    };
    const result = reducer(stateWithTemplates, action).toJS();
    expect(result.selectedFacebookAccount).toEqual(mockAccount);
    expect(result.templates).toEqual([]);
  });

  it.concurrent("should clear templates when SET_WEBPUSH_ACCOUNT is dispatched", () => {
    const stateWithTemplates = initialState.set('templates', [{ id: 1, name: "Template 1" }]);
    const mockAccount = { id: 1, name: "WebPush Account", accountName: "webpush123" };
    const action = {
      type: types.SET_WEBPUSH_ACCOUNT,
      account: mockAccount,
    };
    const result = reducer(stateWithTemplates, action).toJS();
    expect(result.selectedWebPushAccount).toEqual(mockAccount);
    expect(result.templates).toEqual([]);
  });

  it.concurrent("should clear templates even when templates array is empty", () => {
    const emptyTemplatesState = initialState.set('templates', []);
    const mockAccount = { id: 1, name: "WeChat Account" };
    const action = {
      type: types.SET_WECHAT_ACCOUNT,
      weChatAccount: mockAccount,
    };
    const result = reducer(emptyTemplatesState, action).toJS();
    expect(result.selectedWeChatAccount).toEqual(mockAccount);
    expect(result.templates).toEqual([]);
  });

  it.concurrent("should clear templates when switching between different accounts", () => {
    // Set first account with templates
    let state = initialState.set('templates', [{ id: 1, name: "Template 1" }]);
    const weChatAccount = { id: 1, name: "WeChat Account" };
    state = reducer(state, {
      type: types.SET_WECHAT_ACCOUNT,
      weChatAccount,
    });
    expect(state.toJS().templates).toEqual([]);

    // Add templates again
    state = state.set('templates', [{ id: 2, name: "Template 2" }]);

    // Switch to different account - should clear templates again
    const lineAccount = { id: 2, name: "Line Account" };
    const result = reducer(state, {
      type: types.SET_LINE_ACCOUNT,
      account: lineAccount,
    }).toJS();
    expect(result.selectedLineAccount).toEqual(lineAccount);
    expect(result.templates).toEqual([]);
  });
});

describe("test reducer - archive actions", () => {
  afterEach(() => {
    jest.clearAllMocks();
  });

  it("should handle SET_ARCHIVE_FILTER", () => {
    const action = { type: types.SET_ARCHIVE_FILTER, filter: 'archived' };
    const result = reducer(initialState, action).toJS();
    expect(result.archiveFilter).toBe('archived');
    expect(result.templates).toEqual([]);
    expect(result.selectedTemplateIds).toEqual([]);
  });

  it("should handle SET_ARCHIVED_MODE with isArchived true", () => {
    const action = { type: types.SET_ARCHIVED_MODE, isArchived: true };
    const result = reducer(initialState, action).toJS();
    expect(result.isArchivedMode).toBe(true);
    expect(result.archiveFilter).toBe('archived');
    expect(result.templates).toEqual([]);
    expect(result.selectedTemplateIds).toEqual([]);
  });

  it("should handle SET_ARCHIVED_MODE with isArchived false", () => {
    const action = { type: types.SET_ARCHIVED_MODE, isArchived: false };
    const result = reducer(initialState, action).toJS();
    expect(result.isArchivedMode).toBe(false);
    expect(result.archiveFilter).toBe('active');
  });

  it("should handle TOGGLE_TEMPLATE_SELECTION - add id", () => {
    const action = { type: types.TOGGLE_TEMPLATE_SELECTION, id: 'id1' };
    const result = reducer(initialState, action).toJS();
    expect(result.selectedTemplateIds).toEqual(['id1']);
  });

  it("should handle TOGGLE_TEMPLATE_SELECTION - remove id if already selected", () => {
    const { fromJS } = require('immutable');
    const stateWithSelected = initialState.set('selectedTemplateIds', fromJS(['id1', 'id2']));
    const action = { type: types.TOGGLE_TEMPLATE_SELECTION, id: 'id1' };
    const result = reducer(stateWithSelected, action).toJS();
    expect(result.selectedTemplateIds).toEqual(['id2']);
  });

  it("should handle TOGGLE_TEMPLATE_SELECTION - add id when selectedTemplateIds is a plain array (legacy state)", () => {
    // Covers the Array.isArray branch of the defensive fallback
    const stateWithPlainArray = initialState.set('selectedTemplateIds', ['id1']);
    const action = { type: types.TOGGLE_TEMPLATE_SELECTION, id: 'id2' };
    const result = reducer(stateWithPlainArray, action).toJS();
    expect(result.selectedTemplateIds).toEqual(['id1', 'id2']);
  });

  it("should handle TOGGLE_TEMPLATE_SELECTION - remove id when selectedTemplateIds is a plain array (legacy state)", () => {
    // Covers the Array.isArray branch of the defensive fallback
    const stateWithPlainArray = initialState.set('selectedTemplateIds', ['id1', 'id2']);
    const action = { type: types.TOGGLE_TEMPLATE_SELECTION, id: 'id1' };
    const result = reducer(stateWithPlainArray, action).toJS();
    expect(result.selectedTemplateIds).toEqual(['id2']);
  });

  it("should handle TOGGLE_TEMPLATE_SELECTION - add id when selectedTemplateIds is undefined (stale persisted state)", () => {
    // Covers the final fallback to [] when rawSelected is neither Immutable nor Array
    const stateWithUndefined = initialState.set('selectedTemplateIds', undefined);
    const action = { type: types.TOGGLE_TEMPLATE_SELECTION, id: 'id1' };
    const result = reducer(stateWithUndefined, action).toJS();
    expect(result.selectedTemplateIds).toEqual(['id1']);
  });

  it("should handle SELECT_ALL_TEMPLATES", () => {
    const action = { type: types.SELECT_ALL_TEMPLATES, ids: ['id1', 'id2', 'id3'] };
    const result = reducer(initialState, action).toJS();
    expect(result.selectedTemplateIds).toEqual(['id1', 'id2', 'id3']);
  });

  it("should handle CLEAR_TEMPLATE_SELECTION", () => {
    const { fromJS } = require('immutable');
    const stateWithSelected = initialState.set('selectedTemplateIds', fromJS(['id1', 'id2']));
    const action = { type: types.CLEAR_TEMPLATE_SELECTION };
    const result = reducer(stateWithSelected, action).toJS();
    expect(result.selectedTemplateIds).toEqual([]);
  });

  it("should handle ARCHIVE_TEMPLATE_REQUEST", () => {
    const action = { type: types.ARCHIVE_TEMPLATE_REQUEST };
    const result = reducer(initialState, action).toJS();
    expect(result.archiveInProgress).toBe(true);
  });

  it("should handle ARCHIVE_TEMPLATE_SUCCESS", () => {
    const action = { type: types.ARCHIVE_TEMPLATE_SUCCESS };
    const result = reducer(initialState, action).toJS();
    expect(result.archiveInProgress).toBe(false);
  });

  it("should remove archived template id from selectedTemplateIds on ARCHIVE_TEMPLATE_SUCCESS", () => {
    const { fromJS } = require('immutable');
    const stateWithSelected = initialState.set('selectedTemplateIds', fromJS(['id1', 'id2', 'id3']));
    const action = { type: types.ARCHIVE_TEMPLATE_SUCCESS, id: 'id2' };
    const result = reducer(stateWithSelected, action).toJS();
    expect(result.archiveInProgress).toBe(false);
    expect(result.selectedTemplateIds).toEqual(['id1', 'id3']);
  });

  it("should handle ARCHIVE_TEMPLATE_FAILURE", () => {
    const action = { type: types.ARCHIVE_TEMPLATE_FAILURE };
    const result = reducer(initialState, action).toJS();
    expect(result.archiveInProgress).toBe(false);
  });

  it("should handle UNARCHIVE_TEMPLATE_REQUEST", () => {
    const action = { type: types.UNARCHIVE_TEMPLATE_REQUEST };
    const result = reducer(initialState, action).toJS();
    expect(result.unarchiveInProgress).toBe(true);
  });

  it("should handle UNARCHIVE_TEMPLATE_SUCCESS", () => {
    const action = { type: types.UNARCHIVE_TEMPLATE_SUCCESS };
    const result = reducer(initialState, action).toJS();
    expect(result.unarchiveInProgress).toBe(false);
  });

  it("should remove unarchived template id from selectedTemplateIds on UNARCHIVE_TEMPLATE_SUCCESS", () => {
    const { fromJS } = require('immutable');
    const stateWithSelected = initialState.set('selectedTemplateIds', fromJS(['id1', 'id2', 'id3']));
    const action = { type: types.UNARCHIVE_TEMPLATE_SUCCESS, id: 'id1' };
    const result = reducer(stateWithSelected, action).toJS();
    expect(result.unarchiveInProgress).toBe(false);
    expect(result.selectedTemplateIds).toEqual(['id2', 'id3']);
  });

  it("should handle UNARCHIVE_TEMPLATE_FAILURE", () => {
    const action = { type: types.UNARCHIVE_TEMPLATE_FAILURE };
    const result = reducer(initialState, action).toJS();
    expect(result.unarchiveInProgress).toBe(false);
  });

  it("should handle BULK_ARCHIVE_REQUEST", () => {
    const action = { type: types.BULK_ARCHIVE_REQUEST };
    const result = reducer(initialState, action).toJS();
    expect(result.bulkArchiveInProgress).toBe(true);
  });

  it("should handle BULK_ARCHIVE_SUCCESS", () => {
    const { fromJS } = require('immutable');
    const stateWithSelected = initialState.set('selectedTemplateIds', fromJS(['id1']));
    const action = { type: types.BULK_ARCHIVE_SUCCESS };
    const result = reducer(stateWithSelected, action).toJS();
    expect(result.bulkArchiveInProgress).toBe(false);
    expect(result.selectedTemplateIds).toEqual([]);
  });

  it("should handle BULK_ARCHIVE_FAILURE", () => {
    const action = { type: types.BULK_ARCHIVE_FAILURE };
    const result = reducer(initialState, action).toJS();
    expect(result.bulkArchiveInProgress).toBe(false);
  });

  it("should handle BULK_UNARCHIVE_REQUEST", () => {
    const action = { type: types.BULK_UNARCHIVE_REQUEST };
    const result = reducer(initialState, action).toJS();
    expect(result.bulkUnarchiveInProgress).toBe(true);
  });

  it("should handle BULK_UNARCHIVE_SUCCESS", () => {
    const { fromJS } = require('immutable');
    const stateWithSelected = initialState.set('selectedTemplateIds', fromJS(['id1']));
    const action = { type: types.BULK_UNARCHIVE_SUCCESS };
    const result = reducer(stateWithSelected, action).toJS();
    expect(result.bulkUnarchiveInProgress).toBe(false);
    expect(result.selectedTemplateIds).toEqual([]);
  });

  it("should handle BULK_UNARCHIVE_FAILURE", () => {
    const action = { type: types.BULK_UNARCHIVE_FAILURE };
    const result = reducer(initialState, action).toJS();
    expect(result.bulkUnarchiveInProgress).toBe(false);
  });
});
