import SideModal, { type ISideModalProps } from "@ax/components/SideModal";
import { parseTheme } from "@ax/helpers";
import globalTheme from "@ax/themes/theme.json";

import { cleanup, fireEvent, render, screen } from "@testing-library/react";
import { type CalledWithMock, mock } from "jest-mock-extended";
import { ThemeProvider } from "styled-components";

// Mock schemas to prevent getPageSchemas from accessing schemasService
jest.mock("@ax/schemas", () => ({
	getPageSchemas: jest.fn(() => ({})),
	getFixedSchemas: jest.fn(() => ({})),
}));

afterEach(cleanup);

const defaultProps = mock<ISideModalProps>();

describe("SideModal component rendering", () => {
	it("should render the component visible if isOpen is true", () => {
		const handleClickMock = jest.fn();
		const toggleModalMock = jest.fn() as CalledWithMock<void, []> & (() => void);
		defaultProps.categories = [
			{ featured: true, label: "All", value: "all" },
			{ label: "Articles And Events", value: "articlesAndEvents" },
		];
		defaultProps.isOpen = true;
		defaultProps.theme = "default-theme";
		defaultProps.whiteList = ["EventsDistributor", "ArticlesDistributor"];
		defaultProps.onClick = handleClickMock;
		defaultProps.toggleModal = toggleModalMock;
		defaultProps.optionsType = "modules";

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const sideModal = screen.getByTestId("side-modal");
		expect(sideModal).toBeTruthy();
		const styles = getComputedStyle(sideModal);
		expect(styles.left).toEqual("0px");
	});

	it("should render the component hidden if isOpen is false", () => {
		const handleClickMock = jest.fn();
		const toggleModalMock = jest.fn() as CalledWithMock<void, []> & (() => void);
		defaultProps.categories = [
			{ featured: true, label: "All", value: "all" },
			{ label: "Articles And Events", value: "articlesAndEvents" },
		];
		defaultProps.isOpen = false;
		defaultProps.theme = "default-theme";
		defaultProps.whiteList = ["EventsDistributor", "ArticlesDistributor"];
		defaultProps.onClick = handleClickMock;
		defaultProps.toggleModal = toggleModalMock;
		defaultProps.optionsType = "modules";

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const sideModal = screen.getByTestId("side-modal");
		expect(sideModal).toBeTruthy();
		const styles = getComputedStyle(sideModal);
		expect(styles.left).toEqual("-999px");
	});

	it("should render optiontype as title", () => {
		defaultProps.isOpen = true;
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const sideModalTitle = screen.getByTestId("side-modal-title");
		expect(sideModalTitle).toBeTruthy();
		expect(sideModalTitle.textContent).toEqual("modules");
	});

	it("should render close button", () => {
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const closeButton = screen.getByTestId("side-modal-close-button");
		expect(closeButton).toBeTruthy();
	});

	it("should render options", () => {
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const options = screen.getAllByTestId("side-modal-option");
		expect(options).toBeTruthy();
		expect(options.length).toEqual(2);
	});

	it("should render option thumbnails", () => {
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const thumbnails = screen.getAllByTestId("side-modal-option-img");
		expect(thumbnails).toBeTruthy();
		expect(thumbnails.length).toEqual(2);
	});

	it("should render all options when All filter is selected", () => {
		const handleClickMock = jest.fn();
		const toggleModalMock = jest.fn() as CalledWithMock<void, []> & (() => void);
		defaultProps.categories = [
			{ featured: true, label: "All", value: "all" },
			{ label: "Content", value: "content" },
			{ label: "Collections", value: "collections" },
		];
		defaultProps.isOpen = true;
		defaultProps.theme = "default-theme";
		defaultProps.whiteList = ["BasicContent", "CardCollection"];
		defaultProps.onClick = handleClickMock;
		defaultProps.toggleModal = toggleModalMock;
		defaultProps.optionsType = "modules";

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);
		const filters = screen.getAllByTestId("side-modal-nav-link");
		expect(filters).toBeTruthy();
		expect(filters.length).toEqual(3);
		const allFilter = filters[0];
		expect(allFilter.textContent).toEqual("All");
		const links = screen.getAllByTestId("side-modal-link");
		const allOptionLink = links[0];
		const selectedStyles = getComputedStyle(allOptionLink);
		expect(selectedStyles.color).toEqual("rgb(32, 34, 76)");
		const options = screen.getAllByTestId("side-modal-option");
		expect(options).toBeTruthy();
		expect(options.length).toEqual(2);
		expect(options[0].textContent).toEqual("Basic Content");
		expect(options[1].textContent).toEqual("Card Collection");
	});

	it("should render components modal if option type is components", () => {
		const handleClickMock = jest.fn();
		const toggleModalMock = jest.fn() as CalledWithMock<void, []> & (() => void);
		defaultProps.componentOptions = {
			image: { component: "LinkableImage", editorID: 11, parentEditorID: 6 },
			video: { component: "Video", editorID: 12, parentEditorID: 6 },
		};
		defaultProps.isOpen = true;
		defaultProps.theme = "default-theme";
		defaultProps.whiteList = ["LinkableImage", "Video"];
		defaultProps.onClick = handleClickMock;
		defaultProps.toggleModal = toggleModalMock;
		defaultProps.optionsType = "components";

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);
		const options = screen.getAllByTestId("side-modal-option");
		expect(options).toBeTruthy();
		expect(options.length).toEqual(2);
	});
});

describe("SideModal component events", () => {
	it("should call handle click and toggle modal on click option", () => {
		const handleClickMock = jest.fn();
		const toggleModalMock = jest.fn() as CalledWithMock<void, []> & (() => void);
		defaultProps.categories = [
			{ featured: true, label: "All", value: "all" },
			{ label: "Articles And Events", value: "articlesAndEvents" },
		];
		defaultProps.componentOptions = undefined;
		defaultProps.isOpen = true;
		defaultProps.theme = "default-theme";
		defaultProps.whiteList = ["Accordion", "AddressCollection"];
		defaultProps.onClick = handleClickMock;
		defaultProps.toggleModal = toggleModalMock;
		defaultProps.optionsType = "modules";

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const options = screen.getAllByTestId("side-modal-option");
		expect(options).toBeTruthy();
		expect(options.length).toEqual(2);
		const option = options[0];
		fireEvent.click(option);
		expect(handleClickMock).toHaveBeenCalled();
		expect(toggleModalMock).toHaveBeenCalled();
	});

	it("should select filter on click", () => {
		const handleClickMock = jest.fn();
		const toggleModalMock = jest.fn() as CalledWithMock<void, []> & (() => void);
		defaultProps.categories = [
			{ featured: true, label: "All", value: "all" },
			{ label: "Content", value: "content" },
			{ label: "Collections", value: "collections" },
		];
		defaultProps.isOpen = true;
		defaultProps.theme = "default-theme";
		defaultProps.whiteList = ["BasicContent", "CardCollection"];
		defaultProps.onClick = handleClickMock;
		defaultProps.toggleModal = toggleModalMock;
		defaultProps.optionsType = "modules";

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const filters = screen.getAllByTestId("side-modal-nav-link");
		expect(filters).toBeTruthy();
		expect(filters.length).toEqual(3);
		const allFilter = filters[0];
		const contentFilter = filters[1];
		expect(allFilter.textContent).toEqual("All");
		expect(contentFilter.textContent).toEqual("Content");
		const links = screen.getAllByTestId("side-modal-link");
		expect(links).toBeTruthy();
		expect(links.length).toEqual(3);
		const contentOptionLink = links[1];
		const notSelectedStyles = getComputedStyle(contentOptionLink);
		expect(notSelectedStyles.color).toEqual("rgba(32, 34, 76, 0.6)");
		fireEvent.click(contentFilter);
		const selectedStyles = getComputedStyle(contentOptionLink);
		expect(selectedStyles.color).toEqual("rgb(32, 34, 76)");
	});

	it("should filter by category on click", () => {
		const handleClickMock = jest.fn();
		const toggleModalMock = jest.fn() as CalledWithMock<void, []> & (() => void);
		defaultProps.categories = [
			{ featured: true, label: "All", value: "all" },
			{ label: "Content", value: "content" },
			{ label: "Collections", value: "collections" },
		];
		defaultProps.isOpen = true;
		defaultProps.theme = "default-theme";
		defaultProps.whiteList = ["BasicContent", "CardCollection"];
		defaultProps.onClick = handleClickMock;
		defaultProps.toggleModal = toggleModalMock;
		defaultProps.optionsType = "modules";

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const filters = screen.getAllByTestId("side-modal-nav-link");
		const options = screen.getAllByTestId("side-modal-option");
		expect(options.length).toEqual(2);
		expect(filters).toBeTruthy();
		expect(filters.length).toEqual(3);
		const contentFilter = filters[1];
		expect(contentFilter.textContent).toEqual("Content");
		fireEvent.click(contentFilter);
		expect(options.length).toEqual(2);
	});

	it("should filter by query", () => {
		const handleClickMock = jest.fn();
		const toggleModalMock = jest.fn() as CalledWithMock<void, []> & (() => void);
		defaultProps.categories = [
			{ featured: true, label: "All", value: "all" },
			{ label: "Content", value: "content" },
			{ label: "Collections", value: "collections" },
		];
		defaultProps.isOpen = true;
		defaultProps.theme = "default-theme";
		defaultProps.whiteList = ["BasicContent", "CardCollection"];
		defaultProps.onClick = handleClickMock;
		defaultProps.toggleModal = toggleModalMock;
		defaultProps.optionsType = "modules";
		defaultProps.showSearch = true;

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const searchFieldWrapper = screen.getByTestId("search-field-wrapper");
		expect(searchFieldWrapper).toBeTruthy();
		const input = screen.getByTestId("search-input");
		fireEvent.click(searchFieldWrapper);
		fireEvent.change(input, { target: { value: "Basic content" } });
		fireEvent.keyDown(input, { key: "Enter", code: "Enter", charCode: 13 });
		const options = screen.getAllByTestId("side-modal-option");
		expect(options.length).toEqual(1);
		expect(options[0].textContent).toEqual("Basic Content");
	});

	it("should call toggle modal on click outside the modal", () => {
		const map: any = {};

		document.addEventListener = jest.fn((event, callback) => {
			map[event] = callback;
		});

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		map.mousedown({
			target: document.body,
		});

		expect(defaultProps.toggleModal).toHaveBeenCalled();
	});

	it("should not call toggle modal on click inside the modal", () => {
		const map: any = {};

		document.addEventListener = jest.fn((event, callback) => {
			map[event] = callback;
		});

		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<SideModal {...defaultProps} />
			</ThemeProvider>,
		);

		const title = screen.getByTestId("side-modal-title");

		map.mousedown({
			target: title,
		});

		expect(defaultProps.toggleModal).not.toHaveBeenCalled();
	});
});
