import React from "react";
import { mount } from "enzyme";
import { Provider } from "react-redux";
import { INITIAL_STATE, reducers } from "common/Reducers.sys.mjs";
import { combineReducers, createStore } from "redux";
import {
  Widgets,
  resetTimerToDefaults,
} from "content-src/components/Widgets/Widgets";
import { Lists } from "content-src/components/Widgets/Lists/Lists";
import { actionTypes as at } from "common/Actions.mjs";
import { FocusTimer } from "content-src/components/Widgets/FocusTimer/FocusTimer";

const PREF_WIDGETS_ENABLED = "widgets.enabled";
const PREF_WIDGETS_LISTS_ENABLED = "widgets.lists.enabled";
const PREF_WIDGETS_SYSTEM_LISTS_ENABLED = "widgets.system.lists.enabled";
const PREF_WIDGETS_TIMER_ENABLED = "widgets.focusTimer.enabled";
const PREF_WIDGETS_SYSTEM_TIMER_ENABLED = "widgets.system.focusTimer.enabled";
const PREF_WIDGETS_FEEDBACK_ENABLED = "widgets.feedback.enabled";
const PREF_WIDGETS_HIDE_ALL_TOAST_ENABLED = "widgets.hideAllToast.enabled";

function WrapWithProvider({ children, state = INITIAL_STATE }) {
  const store = createStore(combineReducers(reducers), state);
  return <Provider store={store}>{children}</Provider>;
}

describe("<Widgets>", () => {
  it("should render and show <Lists> if list prefs are enabled", () => {
    const state = {
      ...INITIAL_STATE,
      Prefs: {
        ...INITIAL_STATE.Prefs,
        values: {
          ...INITIAL_STATE.Prefs.values,
          [PREF_WIDGETS_ENABLED]: true,
          [PREF_WIDGETS_LISTS_ENABLED]: true,
          [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true,
        },
      },
    };
    const wrapper = mount(
      <WrapWithProvider state={state}>
        <Widgets />
      </WrapWithProvider>
    );
    assert.ok(wrapper.exists());
    assert.ok(wrapper.find(".widgets-container").exists());
    assert.ok(wrapper.find(Lists).exists());
  });

  it("should render and show <FocusTimer> if timer prefs are enabled", () => {
    const state = {
      ...INITIAL_STATE,
      Prefs: {
        ...INITIAL_STATE.Prefs,
        values: {
          ...INITIAL_STATE.Prefs.values,
          [PREF_WIDGETS_ENABLED]: true,
          [PREF_WIDGETS_TIMER_ENABLED]: true,
          [PREF_WIDGETS_SYSTEM_TIMER_ENABLED]: true,
        },
      },
    };
    const wrapper = mount(
      <WrapWithProvider state={state}>
        <Widgets />
      </WrapWithProvider>
    );
    assert.ok(wrapper.exists());
    assert.ok(wrapper.find(".widgets-container").exists());
    assert.ok(wrapper.find(FocusTimer).exists());
  });

  it("should render nothing when widgetsEnabled is false, even if individual widget prefs are on", () => {
    const state = {
      ...INITIAL_STATE,
      Prefs: {
        ...INITIAL_STATE.Prefs,
        values: {
          ...INITIAL_STATE.Prefs.values,
          [PREF_WIDGETS_ENABLED]: false,
          [PREF_WIDGETS_LISTS_ENABLED]: true,
          [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true,
          [PREF_WIDGETS_TIMER_ENABLED]: true,
          [PREF_WIDGETS_SYSTEM_TIMER_ENABLED]: true,
        },
      },
    };
    const wrapper = mount(
      <WrapWithProvider state={state}>
        <Widgets />
      </WrapWithProvider>
    );
    assert.ok(!wrapper.find(".widgets-wrapper").exists());
    assert.ok(!wrapper.find(Lists).exists());
    assert.ok(!wrapper.find(FocusTimer).exists());
  });

  it("should not render FocusTimer when timer pref is disabled", () => {
    const state = {
      ...INITIAL_STATE,
      Prefs: {
        ...INITIAL_STATE.Prefs,
        values: {
          ...INITIAL_STATE.Prefs.values,
          [PREF_WIDGETS_TIMER_ENABLED]: false,
          [PREF_WIDGETS_SYSTEM_TIMER_ENABLED]: true,
        },
      },
    };
    const wrapper = mount(
      <WrapWithProvider state={state}>
        <Widgets />
      </WrapWithProvider>
    );
    assert.ok(!wrapper.find(FocusTimer).exists());
  });

  describe("resetTimerToDefaults", () => {
    it("should dispatch WIDGETS_TIMER_RESET with focus timer defaults", () => {
      const dispatch = sinon.spy();
      const timerType = "focus";

      resetTimerToDefaults(dispatch, timerType);

      const resetCall = dispatch
        .getCalls()
        .find(call => call.args[0]?.type === at.WIDGETS_TIMER_RESET);
      const setTypeCall = dispatch
        .getCalls()
        .find(call => call.args[0]?.type === at.WIDGETS_TIMER_SET_TYPE);

      assert.ok(resetCall, "should dispatch WIDGETS_TIMER_RESET");
      assert.ok(setTypeCall, "should dispatch WIDGETS_TIMER_SET_TYPE");
      assert.equal(
        resetCall.args[0].data.duration,
        1500,
        "should reset focus to 25 minutes"
      );
      assert.equal(resetCall.args[0].data.initialDuration, 1500);
      assert.equal(resetCall.args[0].data.timerType, "focus");
      assert.equal(setTypeCall.args[0].data.timerType, "focus");
    });

    it("should dispatch WIDGETS_TIMER_RESET with break timer defaults", () => {
      const dispatch = sinon.spy();
      const timerType = "break";

      resetTimerToDefaults(dispatch, timerType);

      const resetCall = dispatch
        .getCalls()
        .find(call => call.args[0]?.type === at.WIDGETS_TIMER_RESET);

      assert.ok(resetCall, "should dispatch WIDGETS_TIMER_RESET");
      assert.equal(
        resetCall.args[0].data.duration,
        300,
        "should reset break to 5 minutes"
      );
      assert.equal(resetCall.args[0].data.initialDuration, 300);
      assert.equal(resetCall.args[0].data.timerType, "break");
    });
  });

  describe("handleHideAllWidgets", () => {
    let wrapper;
    let state;
    let store;

    beforeEach(() => {
      state = {
        ...INITIAL_STATE,
        Prefs: {
          ...INITIAL_STATE.Prefs,
          values: {
            ...INITIAL_STATE.Prefs.values,
            [PREF_WIDGETS_ENABLED]: true,
            [PREF_WIDGETS_LISTS_ENABLED]: true,
            [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true,
            [PREF_WIDGETS_TIMER_ENABLED]: true,
            [PREF_WIDGETS_SYSTEM_TIMER_ENABLED]: true,
          },
        },
      };
      store = createStore(combineReducers(reducers), state);
      sinon.spy(store, "dispatch");
      wrapper = mount(
        <Provider store={store}>
          <Widgets />
        </Provider>
      );
    });

    afterEach(() => {
      store.dispatch.restore();
    });

    it("should dispatch SetPref actions when hide button is clicked", () => {
      const hideButton = wrapper.find("#hide-all-widgets-button");
      assert.ok(hideButton.exists(), "hide all button should exist");

      // Get the onClick handler and call it
      const onClickHandler = hideButton.prop("onClick");
      assert.ok(onClickHandler, "onClick handler should exist");
      onClickHandler({ preventDefault: () => {} });

      const allCalls = store.dispatch.getCalls();
      const setPrefCalls = allCalls.filter(
        call => call.args[0]?.type === at.SET_PREF
      );

      assert.equal(
        setPrefCalls.length,
        2,
        `should dispatch two SetPref actions, got ${setPrefCalls.length}.`
      );

      const listsPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === PREF_WIDGETS_LISTS_ENABLED
      );
      const timerPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === PREF_WIDGETS_TIMER_ENABLED
      );

      assert.ok(listsPrefCall, "should dispatch SetPref for lists");
      assert.equal(
        listsPrefCall.args[0].data.value,
        false,
        "should set lists pref to false"
      );

      assert.ok(timerPrefCall, "should dispatch SetPref for timer");
      assert.equal(
        timerPrefCall.args[0].data.value,
        false,
        "should set timer pref to false"
      );
    });

    it("should dispatch SetPref actions when Enter key is pressed on hide button", () => {
      const hideButton = wrapper.find("#hide-all-widgets-button");

      // Trigger onKeyDown handler directly with Enter key
      hideButton.prop("onKeyDown")({ key: "Enter", preventDefault: () => {} });

      const setPrefCalls = store.dispatch
        .getCalls()
        .filter(call => call.args[0]?.type === at.SET_PREF);

      assert.equal(
        setPrefCalls.length,
        2,
        "should dispatch two SetPref actions"
      );

      const listsPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === PREF_WIDGETS_LISTS_ENABLED
      );
      const timerPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === PREF_WIDGETS_TIMER_ENABLED
      );

      assert.ok(listsPrefCall, "should dispatch SetPref for lists");
      assert.equal(
        listsPrefCall.args[0].data.value,
        false,
        "should set lists pref to false"
      );

      assert.ok(timerPrefCall, "should dispatch SetPref for timer");
      assert.equal(
        timerPrefCall.args[0].data.value,
        false,
        "should set timer pref to false"
      );
    });

    it("should dispatch SetPref actions when Space key is pressed on hide button", () => {
      const hideButton = wrapper.find("#hide-all-widgets-button");

      // Trigger onKeyDown handler directly with Space key
      hideButton.prop("onKeyDown")({ key: " ", preventDefault: () => {} });

      const setPrefCalls = store.dispatch
        .getCalls()
        .filter(call => call.args[0]?.type === at.SET_PREF);

      assert.equal(
        setPrefCalls.length,
        2,
        "should dispatch two SetPref actions"
      );

      const listsPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === PREF_WIDGETS_LISTS_ENABLED
      );
      const timerPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === PREF_WIDGETS_TIMER_ENABLED
      );

      assert.ok(listsPrefCall, "should dispatch SetPref for lists");
      assert.equal(
        listsPrefCall.args[0].data.value,
        false,
        "should set lists pref to false"
      );

      assert.ok(timerPrefCall, "should dispatch SetPref for timer");
      assert.equal(
        timerPrefCall.args[0].data.value,
        false,
        "should set timer pref to false"
      );
    });

    it("should not dispatch SetPref actions when other keys are pressed", () => {
      const hideButton = wrapper.find("#hide-all-widgets-button");

      const testKeys = ["Escape", "Tab", "a", "ArrowDown"];

      for (const key of testKeys) {
        store.dispatch.resetHistory();
        // Trigger onKeyDown handler directly
        hideButton.prop("onKeyDown")({ key });

        const setPrefCalls = store.dispatch
          .getCalls()
          .filter(call => call.args[0]?.type === at.SET_PREF);

        assert.equal(
          setPrefCalls.length,
          0,
          `should not dispatch SetPref for key: ${key}`
        );
      }
    });

    it("should dispatch WIDGETS_CONTAINER_ACTION telemetry when hide button is clicked", () => {
      const hideButton = wrapper.find("#hide-all-widgets-button");
      hideButton.prop("onClick")({ preventDefault: () => {} });

      const dispatchedActions = store.dispatch
        .getCalls()
        .map(call => call.args[0]);

      const containerAction = dispatchedActions.find(
        action => action.type === at.WIDGETS_CONTAINER_ACTION
      );

      assert.ok(
        containerAction,
        "should dispatch WIDGETS_CONTAINER_ACTION event"
      );
      assert.equal(containerAction.data.action_type, "hide_all");
      assert.equal(
        containerAction.data.widget_size,
        "medium",
        "widget_size should be medium when widgets.system.maximized is false"
      );
      assert.equal(
        containerAction.data.action_value,
        undefined,
        "hide_all should not have action_value"
      );
    });

    it("should dispatch WIDGETS_CONTAINER_ACTION with medium size when widgets are maximized", () => {
      const maximizedState = {
        ...state,
        Prefs: {
          ...state.Prefs,
          values: {
            ...state.Prefs.values,
            "widgets.maximized": true,
            "widgets.system.maximized": true,
          },
        },
      };
      const maximizedStore = createStore(
        combineReducers(reducers),
        maximizedState
      );
      sinon.spy(maximizedStore, "dispatch");
      const maximizedWrapper = mount(
        <Provider store={maximizedStore}>
          <Widgets />
        </Provider>
      );

      const hideButton = maximizedWrapper.find("#hide-all-widgets-button");
      hideButton.prop("onClick")({ preventDefault: () => {} });

      const dispatchedActions = maximizedStore.dispatch
        .getCalls()
        .map(call => call.args[0]);

      const containerAction = dispatchedActions.find(
        action => action.type === at.WIDGETS_CONTAINER_ACTION
      );

      assert.ok(containerAction, "should dispatch WIDGETS_CONTAINER_ACTION");
      assert.equal(
        containerAction.data.widget_size,
        "medium",
        "should report medium size when maximized"
      );
      maximizedStore.dispatch.restore();
    });

    it("should dispatch WIDGETS_ENABLED for each enabled widget when hide button is clicked", () => {
      const hideButton = wrapper.find("#hide-all-widgets-button");
      hideButton.prop("onClick")({ preventDefault: () => {} });

      const dispatchedActions = store.dispatch
        .getCalls()
        .map(call => call.args[0]);

      const widgetsEnabledActions = dispatchedActions.filter(
        action => action.type === at.WIDGETS_ENABLED
      );

      assert.equal(
        widgetsEnabledActions.length,
        2,
        "should dispatch WIDGETS_ENABLED for both lists and timer"
      );

      const listsEnabledAction = widgetsEnabledActions.find(
        action => action.data.widget_name === "lists"
      );
      const timerEnabledAction = widgetsEnabledActions.find(
        action => action.data.widget_name === "focus_timer"
      );

      assert.ok(
        listsEnabledAction,
        "should dispatch WIDGETS_ENABLED for lists"
      );
      assert.equal(listsEnabledAction.data.widget_source, "widget");
      assert.equal(listsEnabledAction.data.enabled, false);
      assert.equal(listsEnabledAction.data.widget_size, "medium");

      assert.ok(
        timerEnabledAction,
        "should dispatch WIDGETS_ENABLED for timer"
      );
      assert.equal(timerEnabledAction.data.widget_source, "widget");
      assert.equal(timerEnabledAction.data.enabled, false);
      assert.equal(timerEnabledAction.data.widget_size, "medium");
    });

    it("should dispatch WIDGETS_ENABLED only for enabled widgets", () => {
      const partialState = {
        ...state,
        Prefs: {
          ...state.Prefs,
          values: {
            ...state.Prefs.values,
            [PREF_WIDGETS_LISTS_ENABLED]: true,
            [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true,
            [PREF_WIDGETS_TIMER_ENABLED]: false,
            [PREF_WIDGETS_SYSTEM_TIMER_ENABLED]: true,
          },
        },
      };
      const partialStore = createStore(combineReducers(reducers), partialState);
      sinon.spy(partialStore, "dispatch");
      const partialWrapper = mount(
        <Provider store={partialStore}>
          <Widgets />
        </Provider>
      );

      const hideButton = partialWrapper.find("#hide-all-widgets-button");
      hideButton.prop("onClick")({ preventDefault: () => {} });

      const widgetsEnabledActions = partialStore.dispatch
        .getCalls()
        .map(call => call.args[0])
        .filter(action => action.type === at.WIDGETS_ENABLED);

      assert.equal(
        widgetsEnabledActions.length,
        1,
        "should only dispatch WIDGETS_ENABLED for lists (timer is already disabled)"
      );

      const listsEnabledAction = widgetsEnabledActions.find(
        action => action.data.widget_name === "lists"
      );

      assert.ok(
        listsEnabledAction,
        "should dispatch WIDGETS_ENABLED for lists"
      );
      assert.equal(listsEnabledAction.data.enabled, false);

      partialStore.dispatch.restore();
    });

    it("should dispatch WIDGETS_ENABLED with correct widget_size when maximized", () => {
      const maximizedState = {
        ...state,
        Prefs: {
          ...state.Prefs,
          values: {
            ...state.Prefs.values,
            "widgets.maximized": true,
            "widgets.system.maximized": true,
          },
        },
      };
      const maximizedStore = createStore(
        combineReducers(reducers),
        maximizedState
      );
      sinon.spy(maximizedStore, "dispatch");
      const maximizedWrapper = mount(
        <Provider store={maximizedStore}>
          <Widgets />
        </Provider>
      );

      const hideButton = maximizedWrapper.find("#hide-all-widgets-button");
      hideButton.prop("onClick")({ preventDefault: () => {} });

      const widgetsEnabledActions = maximizedStore.dispatch
        .getCalls()
        .map(call => call.args[0])
        .filter(action => action.type === at.WIDGETS_ENABLED);

      assert.equal(widgetsEnabledActions.length, 2);

      widgetsEnabledActions.forEach(action => {
        assert.equal(
          action.data.widget_size,
          "medium",
          "widget_size should be medium when maximized"
        );
      });

      maximizedStore.dispatch.restore();
    });

    it("should dispatch WIDGETS_ENABLED for each enabled widget when Enter key is pressed", () => {
      const hideButton = wrapper.find("#hide-all-widgets-button");
      hideButton.prop("onKeyDown")({ key: "Enter", preventDefault: () => {} });

      const widgetsEnabledActions = store.dispatch
        .getCalls()
        .map(call => call.args[0])
        .filter(action => action.type === at.WIDGETS_ENABLED);

      assert.equal(
        widgetsEnabledActions.length,
        2,
        "should dispatch WIDGETS_ENABLED for both lists and timer"
      );

      const listsEnabledAction = widgetsEnabledActions.find(
        action => action.data.widget_name === "lists"
      );
      const timerEnabledAction = widgetsEnabledActions.find(
        action => action.data.widget_name === "focus_timer"
      );

      assert.ok(
        listsEnabledAction,
        "should dispatch WIDGETS_ENABLED for lists"
      );
      assert.equal(listsEnabledAction.data.widget_source, "widget");
      assert.equal(listsEnabledAction.data.enabled, false);
      assert.equal(listsEnabledAction.data.widget_size, "medium");

      assert.ok(
        timerEnabledAction,
        "should dispatch WIDGETS_ENABLED for timer"
      );
      assert.equal(timerEnabledAction.data.widget_source, "widget");
      assert.equal(timerEnabledAction.data.enabled, false);
      assert.equal(timerEnabledAction.data.widget_size, "medium");
    });
  });

  describe("feedback link", () => {
    let baseState;

    beforeEach(() => {
      baseState = {
        ...INITIAL_STATE,
        Prefs: {
          ...INITIAL_STATE.Prefs,
          values: {
            ...INITIAL_STATE.Prefs.values,
            [PREF_WIDGETS_ENABLED]: true,
            [PREF_WIDGETS_LISTS_ENABLED]: true,
            [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true,
          },
        },
      };
    });

    it("should not render the feedback link when feedbackEnabled is not set", () => {
      const wrapper = mount(
        <WrapWithProvider state={baseState}>
          <Widgets />
        </WrapWithProvider>
      );
      assert.ok(!wrapper.find(".widgets-feedback-link").exists());
    });

    it("should not render the feedback link when feedbackEnabled is false", () => {
      const state = {
        ...baseState,
        Prefs: {
          ...baseState.Prefs,
          values: {
            ...baseState.Prefs.values,
            trainhopConfig: { widgets: { feedbackEnabled: false } },
          },
        },
      };
      const wrapper = mount(
        <WrapWithProvider state={state}>
          <Widgets />
        </WrapWithProvider>
      );
      assert.ok(!wrapper.find(".widgets-feedback-link").exists());
    });

    it("should render the feedback link when trainhopConfig feedbackEnabled is true", () => {
      const state = {
        ...baseState,
        Prefs: {
          ...baseState.Prefs,
          values: {
            ...baseState.Prefs.values,
            trainhopConfig: { widgets: { feedbackEnabled: true } },
          },
        },
      };
      const wrapper = mount(
        <WrapWithProvider state={state}>
          <Widgets />
        </WrapWithProvider>
      );
      assert.ok(wrapper.find(".widgets-feedback-link").exists());
    });

    it("should render the feedback link when the pref is true", () => {
      const state = {
        ...baseState,
        Prefs: {
          ...baseState.Prefs,
          values: {
            ...baseState.Prefs.values,
            [PREF_WIDGETS_FEEDBACK_ENABLED]: true,
          },
        },
      };
      const wrapper = mount(
        <WrapWithProvider state={state}>
          <Widgets />
        </WrapWithProvider>
      );
      assert.ok(wrapper.find(".widgets-feedback-link").exists());
    });

    it("should dispatch OPEN_LINK and WIDGETS_CONTAINER_ACTION when feedback link is clicked", () => {
      const state = {
        ...baseState,
        Prefs: {
          ...baseState.Prefs,
          values: {
            ...baseState.Prefs.values,
            trainhopConfig: { widgets: { feedbackEnabled: true } },
          },
        },
      };
      const store = createStore(combineReducers(reducers), state);
      sinon.spy(store, "dispatch");
      const wrapper = mount(
        <Provider store={store}>
          <Widgets />
        </Provider>
      );

      wrapper.find(".widgets-feedback-link").prop("onClick")({
        preventDefault: () => {},
      });

      const dispatched = store.dispatch.getCalls().map(c => c.args[0]);
      const openLink = dispatched.find(a => a.type === at.OPEN_LINK);
      const containerAction = dispatched.find(
        a => a.type === at.WIDGETS_CONTAINER_ACTION
      );

      assert.ok(openLink, "should dispatch OPEN_LINK");
      assert.ok(containerAction, "should dispatch WIDGETS_CONTAINER_ACTION");
      assert.equal(containerAction.data.action_type, "feedback");
      assert.equal(containerAction.data.widget_size, "medium");

      store.dispatch.restore();
    });

    it("should use a custom URL from trainhopConfig when provided", () => {
      const customUrl = "https://example.com/custom-feedback";
      const state = {
        ...baseState,
        Prefs: {
          ...baseState.Prefs,
          values: {
            ...baseState.Prefs.values,
            trainhopConfig: {
              widgets: {
                feedbackEnabled: true,
                feedbackUrl: customUrl,
              },
            },
          },
        },
      };
      const store = createStore(combineReducers(reducers), state);
      sinon.spy(store, "dispatch");
      const wrapper = mount(
        <Provider store={store}>
          <Widgets />
        </Provider>
      );

      wrapper.find(".widgets-feedback-link").prop("onClick")({
        preventDefault: () => {},
      });

      const dispatched = store.dispatch.getCalls().map(c => c.args[0]);
      const openLink = dispatched.find(a => a.type === at.OPEN_LINK);

      assert.ok(openLink, "should dispatch OPEN_LINK");
      assert.equal(openLink.data.url, customUrl);

      store.dispatch.restore();
    });
  });

  describe("hide all widgets toast", () => {
    let baseState;

    beforeEach(() => {
      baseState = {
        ...INITIAL_STATE,
        Prefs: {
          ...INITIAL_STATE.Prefs,
          values: {
            ...INITIAL_STATE.Prefs.values,
            [PREF_WIDGETS_ENABLED]: true,
            [PREF_WIDGETS_LISTS_ENABLED]: true,
            [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true,
          },
        },
      };
    });

    function clickHideButton(store, wrapper) {
      wrapper.find("#hide-all-widgets-button").prop("onClick")({
        preventDefault: () => {},
      });
      return store.dispatch
        .getCalls()
        .map(c => c.args[0])
        .filter(a => a.type === at.SHOW_TOAST_MESSAGE);
    }

    it("should not dispatch toast when hideAllToastEnabled is not set", () => {
      const store = createStore(combineReducers(reducers), baseState);
      sinon.spy(store, "dispatch");
      const wrapper = mount(
        <Provider store={store}>
          <Widgets />
        </Provider>
      );
      const toastActions = clickHideButton(store, wrapper);
      assert.equal(toastActions.length, 0);
      store.dispatch.restore();
    });

    it("should not dispatch toast when pref is false", () => {
      const state = {
        ...baseState,
        Prefs: {
          ...baseState.Prefs,
          values: {
            ...baseState.Prefs.values,
            [PREF_WIDGETS_HIDE_ALL_TOAST_ENABLED]: false,
          },
        },
      };
      const store = createStore(combineReducers(reducers), state);
      sinon.spy(store, "dispatch");
      const wrapper = mount(
        <Provider store={store}>
          <Widgets />
        </Provider>
      );
      const toastActions = clickHideButton(store, wrapper);
      assert.equal(toastActions.length, 0);
      store.dispatch.restore();
    });

    it("should not dispatch toast when trainhopConfig hideAllToastEnabled is false", () => {
      const state = {
        ...baseState,
        Prefs: {
          ...baseState.Prefs,
          values: {
            ...baseState.Prefs.values,
            trainhopConfig: { widgets: { hideAllToastEnabled: false } },
          },
        },
      };
      const store = createStore(combineReducers(reducers), state);
      sinon.spy(store, "dispatch");
      const wrapper = mount(
        <Provider store={store}>
          <Widgets />
        </Provider>
      );
      const toastActions = clickHideButton(store, wrapper);
      assert.equal(toastActions.length, 0);
      store.dispatch.restore();
    });

    it("should dispatch toast when pref is true", () => {
      const state = {
        ...baseState,
        Prefs: {
          ...baseState.Prefs,
          values: {
            ...baseState.Prefs.values,
            [PREF_WIDGETS_HIDE_ALL_TOAST_ENABLED]: true,
          },
        },
      };
      const store = createStore(combineReducers(reducers), state);
      sinon.spy(store, "dispatch");
      const wrapper = mount(
        <Provider store={store}>
          <Widgets />
        </Provider>
      );
      wrapper.find("#hide-all-widgets-button").prop("onClick")({
        preventDefault: () => {},
      });
      const dispatched = store.dispatch.getCalls().map(c => c.args[0]);
      const toastAction = dispatched.find(
        a => a.data && a.data.toastId === "hideWidgetsToast"
      );
      assert.ok(toastAction, "should dispatch toast action");
      assert.equal(toastAction.data.showNotifications, true);
      store.dispatch.restore();
    });

    it("should dispatch toast when trainhopConfig hideAllToastEnabled is true", () => {
      const state = {
        ...baseState,
        Prefs: {
          ...baseState.Prefs,
          values: {
            ...baseState.Prefs.values,
            trainhopConfig: { widgets: { hideAllToastEnabled: true } },
          },
        },
      };
      const store = createStore(combineReducers(reducers), state);
      sinon.spy(store, "dispatch");
      const wrapper = mount(
        <Provider store={store}>
          <Widgets />
        </Provider>
      );
      wrapper.find("#hide-all-widgets-button").prop("onClick")({
        preventDefault: () => {},
      });
      const dispatched = store.dispatch.getCalls().map(c => c.args[0]);
      const toastAction = dispatched.find(
        a => a.data && a.data.toastId === "hideWidgetsToast"
      );
      assert.ok(toastAction, "should dispatch toast action");
      assert.equal(toastAction.data.showNotifications, true);
      store.dispatch.restore();
    });
  });

  describe("handleToggleMaximize", () => {
    let wrapper;
    let state;
    let store;

    beforeEach(() => {
      state = {
        ...INITIAL_STATE,
        Prefs: {
          ...INITIAL_STATE.Prefs,
          values: {
            ...INITIAL_STATE.Prefs.values,
            [PREF_WIDGETS_ENABLED]: true,
            [PREF_WIDGETS_LISTS_ENABLED]: true,
            [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true,
            "widgets.maximized": false,
            "widgets.system.maximized": true,
          },
        },
      };
      store = createStore(combineReducers(reducers), state);
      sinon.spy(store, "dispatch");
      wrapper = mount(
        <Provider store={store}>
          <Widgets />
        </Provider>
      );
    });

    afterEach(() => {
      store.dispatch.restore();
    });

    it("should dispatch SetPref action when toggle button is clicked", () => {
      const toggleButton = wrapper.find("#toggle-widgets-size-button");
      assert.ok(toggleButton.exists(), "toggle button should exist");

      // Get the onClick handler and call it
      const onClickHandler = toggleButton.prop("onClick");
      assert.ok(onClickHandler, "onClick handler should exist");
      onClickHandler({ preventDefault: () => {} });

      const allCalls = store.dispatch.getCalls();
      const setPrefCalls = allCalls.filter(
        call => call.args[0]?.type === at.SET_PREF
      );

      assert.equal(
        setPrefCalls.length,
        1,
        `should dispatch one SetPref action, got ${setPrefCalls.length}.`
      );

      const maximizedPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === "widgets.maximized"
      );

      assert.ok(maximizedPrefCall, "should dispatch SetPref for maximized");
      assert.equal(
        maximizedPrefCall.args[0].data.value,
        true,
        "should toggle maximized pref to true"
      );
    });

    it("should dispatch SetPref action when Enter key is pressed on toggle button", () => {
      const toggleButton = wrapper.find("#toggle-widgets-size-button");

      // Trigger onKeyDown handler directly with Enter key
      toggleButton.prop("onKeyDown")({
        key: "Enter",
        preventDefault: () => {},
      });

      const setPrefCalls = store.dispatch
        .getCalls()
        .filter(call => call.args[0]?.type === at.SET_PREF);

      assert.equal(
        setPrefCalls.length,
        1,
        "should dispatch one SetPref action"
      );

      const maximizedPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === "widgets.maximized"
      );

      assert.ok(maximizedPrefCall, "should dispatch SetPref for maximized");
      assert.equal(
        maximizedPrefCall.args[0].data.value,
        true,
        "should toggle maximized pref to true"
      );
    });

    it("should dispatch SetPref action when Space key is pressed on toggle button", () => {
      const toggleButton = wrapper.find("#toggle-widgets-size-button");

      // Trigger onKeyDown handler directly with Space key
      toggleButton.prop("onKeyDown")({ key: " ", preventDefault: () => {} });

      const setPrefCalls = store.dispatch
        .getCalls()
        .filter(call => call.args[0]?.type === at.SET_PREF);

      assert.equal(
        setPrefCalls.length,
        1,
        "should dispatch one SetPref action"
      );

      const maximizedPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === "widgets.maximized"
      );

      assert.ok(maximizedPrefCall, "should dispatch SetPref for maximized");
      assert.equal(
        maximizedPrefCall.args[0].data.value,
        true,
        "should toggle maximized pref to true"
      );
    });

    it("should not dispatch SetPref actions when other keys are pressed", () => {
      const toggleButton = wrapper.find("#toggle-widgets-size-button");

      const testKeys = ["Escape", "Tab", "a", "ArrowDown"];

      for (const key of testKeys) {
        store.dispatch.resetHistory();
        // Trigger onKeyDown handler directly
        toggleButton.prop("onKeyDown")({ key });

        const setPrefCalls = store.dispatch
          .getCalls()
          .filter(call => call.args[0]?.type === at.SET_PREF);

        assert.equal(
          setPrefCalls.length,
          0,
          `should not dispatch SetPref for key: ${key}`
        );
      }
    });

    it("should toggle from maximized to minimized state", () => {
      // Update state to start with maximized = true
      const maximizedState = {
        ...INITIAL_STATE,
        Prefs: {
          ...INITIAL_STATE.Prefs,
          values: {
            ...INITIAL_STATE.Prefs.values,
            [PREF_WIDGETS_ENABLED]: true,
            [PREF_WIDGETS_LISTS_ENABLED]: true,
            [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true,
            "widgets.maximized": true,
            "widgets.system.maximized": true,
          },
        },
      };
      const maximizedStore = createStore(
        combineReducers(reducers),
        maximizedState
      );
      sinon.spy(maximizedStore, "dispatch");
      const maximizedWrapper = mount(
        <Provider store={maximizedStore}>
          <Widgets />
        </Provider>
      );

      const toggleButton = maximizedWrapper.find("#toggle-widgets-size-button");
      toggleButton.prop("onClick")({ preventDefault: () => {} });

      const setPrefCalls = maximizedStore.dispatch
        .getCalls()
        .filter(call => call.args[0]?.type === at.SET_PREF);

      const maximizedPrefCall = setPrefCalls.find(
        call => call.args[0].data?.name === "widgets.maximized"
      );

      assert.ok(maximizedPrefCall, "should dispatch SetPref for maximized");
      assert.equal(
        maximizedPrefCall.args[0].data.value,
        false,
        "should toggle maximized pref to false"
      );

      maximizedStore.dispatch.restore();
    });

    it("should dispatch WIDGETS_CONTAINER_ACTION telemetry when toggle button is clicked", () => {
      const toggleButton = wrapper.find("#toggle-widgets-size-button");
      toggleButton.prop("onClick")({ preventDefault: () => {} });

      const dispatchedActions = store.dispatch
        .getCalls()
        .map(call => call.args[0]);

      const containerAction = dispatchedActions.find(
        action => action.type === at.WIDGETS_CONTAINER_ACTION
      );

      assert.ok(
        containerAction,
        "should dispatch WIDGETS_CONTAINER_ACTION event"
      );
      assert.equal(containerAction.data.action_type, "change_size_all");
      assert.equal(containerAction.data.action_value, "maximize_widgets");
      assert.equal(containerAction.data.widget_size, "medium");
    });

    it("should dispatch WIDGETS_CONTAINER_ACTION with correct values when toggling from maximized", () => {
      const maximizedState = {
        ...INITIAL_STATE,
        Prefs: {
          ...INITIAL_STATE.Prefs,
          values: {
            ...INITIAL_STATE.Prefs.values,
            [PREF_WIDGETS_ENABLED]: true,
            [PREF_WIDGETS_LISTS_ENABLED]: true,
            [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true,
            "widgets.maximized": true,
            "widgets.system.maximized": true,
          },
        },
      };
      const maximizedStore = createStore(
        combineReducers(reducers),
        maximizedState
      );
      sinon.spy(maximizedStore, "dispatch");
      const maximizedWrapper = mount(
        <Provider store={maximizedStore}>
          <Widgets />
        </Provider>
      );

      const toggleButton = maximizedWrapper.find("#toggle-widgets-size-button");
      toggleButton.prop("onClick")({ preventDefault: () => {} });

      const dispatchedActions = maximizedStore.dispatch
        .getCalls()
        .map(call => call.args[0]);

      const containerAction = dispatchedActions.find(
        action => action.type === at.WIDGETS_CONTAINER_ACTION
      );

      assert.ok(containerAction, "should dispatch WIDGETS_CONTAINER_ACTION");
      assert.equal(containerAction.data.action_type, "change_size_all");
      assert.equal(
        containerAction.data.action_value,
        "minimize_widgets",
        "action_value should indicate minimize widgets"
      );
      assert.equal(
        containerAction.data.widget_size,
        "small",
        "should report new size (small) after minimizing"
      );

      maximizedStore.dispatch.restore();
    });
  });
});
