import * as React from "react";
import { ThemeProvider } from "styled-components";
import { render, cleanup, screen, fireEvent } from "@testing-library/react";
import "@testing-library/jest-dom";

import { parseTheme } from "@ax/helpers";
import Modal, { IModalProps } from "@ax/components/Modal";
import globalTheme from "@ax/themes/theme.json";

afterEach(cleanup);

describe("Modal component rendering", () => {
	it("should render the component opened whith children", () => {
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
		};

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

		const modalWrapper = screen.getByTestId("modal-wrapper");
		expect(modalWrapper).toBeTruthy();
		const children = screen.getByText("the children");
		expect(children).toBeTruthy();
	});

	it("should not render the component closed", () => {
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: false,
			hide: jest.fn(),
		};

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

		const modalWrapper = screen.queryByTestId("modal-wrapper");
		expect(modalWrapper).toBeFalsy();
	});

	it("should render the component title", () => {
		const titleText = "The Modal Title";
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			title: titleText,
		};

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

		const title = screen.getByText(titleText);
		expect(title).toBeTruthy();
	});

	it("should render the main action button", () => {
		const buttonText = "Main Action Button";
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			mainAction: {
				title: buttonText,
				onClick: jest.fn(),
			},
		};

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

		const mainActionButton = screen.getByText(buttonText).closest("button");
		expect(mainActionButton).toBeTruthy();
	});

	it("should render the main action button disabled", () => {
		const buttonText = "Main Action Button";
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			mainAction: {
				title: buttonText,
				onClick: jest.fn(),
				disabled: true,
			},
		};

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

		const mainActionButton = screen.getByText(buttonText).closest("button");
		expect(mainActionButton).toBeTruthy();
		expect(mainActionButton).toBeDisabled();
	});

	it("should render the secondary action button", () => {
		const buttonText = "Secondary Action Button";
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			secondaryAction: {
				title: buttonText,
				onClick: jest.fn(),
			},
		};

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

		const secondaryActionButton = screen.getByText(buttonText).closest("button");
		expect(secondaryActionButton).toBeTruthy();
	});

	it("should render the component whith overflow hidden", () => {
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			overflow: "hidden",
		};

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

		const modalWrapper = screen.getByTestId("modal-wrapper");
		expect(modalWrapper).toBeTruthy();
		const children = screen.getByText("the children");
		expect(children).toBeTruthy();
	});

	it("should render the component whith size M", () => {
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			size: "M",
		};

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

		const modalComponent = screen.getByTestId("modal-component");
		expect(modalComponent).toBeTruthy();
		expect(modalComponent).toHaveStyle("width: 640px");
	});

	it("should render the component whith size L", () => {
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			size: "L",
		};

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

		const modalComponent = screen.getByTestId("modal-component");
		expect(modalComponent).toBeTruthy();
		expect(modalComponent).toHaveStyle("width: 896px");
	});

	it("should render the component whith size XL", () => {
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			size: "XL",
		};

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

		const modalComponent = screen.getByTestId("modal-component");
		expect(modalComponent).toBeTruthy();
		expect(modalComponent).toHaveStyle("width: 1088px");
	});
});

describe("Modal events", () => {
	it("should call hide on icon button click", () => {
		const hideMock = jest.fn();
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: hideMock,
		};

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

		const modalButton = screen.getByTestId("icon-action-component");
		expect(modalButton).toBeTruthy();
		fireEvent.click(modalButton);
		expect(hideMock).toBeCalledTimes(1);
	});

	it("should call action on main action button click", () => {
		const actionMock = jest.fn();
		const buttonText = "Main Action";
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			mainAction: {
				title: buttonText,
				onClick: actionMock,
			},
		};

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

		const mainActionButton = screen.getByText(buttonText).closest("button");
		expect(mainActionButton).toBeTruthy();
		mainActionButton && fireEvent.click(mainActionButton);
		expect(actionMock).toBeCalledTimes(1);
	});

	it("should not call action on main action button click if disabled", () => {
		const actionMock = jest.fn();
		const buttonText = "Main Action";
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			mainAction: {
				title: buttonText,
				onClick: actionMock,
				disabled: true,
			},
		};

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

		const mainActionButton = screen.getByText(buttonText).closest("button");
		expect(mainActionButton).toBeTruthy();
		mainActionButton && fireEvent.click(mainActionButton);
		expect(actionMock).toBeCalledTimes(0);
	});

	it("should call action on secondary action button click", () => {
		const actionMock = jest.fn();
		const buttonText = "Secondary Action";
		const defaultProps: IModalProps = {
			children: <div>the children</div>,
			isOpen: true,
			hide: jest.fn(),
			secondaryAction: {
				title: buttonText,
				onClick: actionMock,
			},
		};

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

		const secondaryActionButton = screen.getByText(buttonText).closest("button");
		expect(secondaryActionButton).toBeTruthy();
		secondaryActionButton && fireEvent.click(secondaryActionButton);
		expect(actionMock).toBeCalledTimes(1);
	});
});
