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

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

afterEach(cleanup);

const createDefaultProps = (): IButtonProps => mock<IButtonProps>();

describe("Button component rendering", () => {
	it("should render the component with the default button and no icon", () => {
		const props = createDefaultProps();
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<Button {...props} />
			</ThemeProvider>,
		);

		const buttonElement = screen.getByTestId("button-default");
		expect(buttonElement).toBeTruthy();
		const iconElement = screen.queryByTestId("icon-component-");
		expect(iconElement).not.toBeTruthy();
	});

	it("should render the component with the text button and an icon", () => {
		const props = createDefaultProps();
		props.buttonStyle = "text";
		props.icon = "delete";

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

		const buttonElement = screen.getByTestId("button-text");
		expect(buttonElement).toBeTruthy();
		const iconElement = screen.getByTestId("icon-component-delete");
		expect(iconElement).toBeTruthy();
	});

	it("should render the component with the line button", () => {
		const props = createDefaultProps();
		props.buttonStyle = "line";
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<Button {...props} />
			</ThemeProvider>,
		);

		const buttonElement = screen.getByTestId("button-line-inverse");
		expect(buttonElement).toBeTruthy();
	});

	it("should render the component with a className", () => {
		const props = createDefaultProps();
		props.className = "my-class";
		props.buttonStyle = "line";
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<Button {...props} />
			</ThemeProvider>,
		);

		const buttonElement = screen.getByTestId("button-line-inverse");
		expect(buttonElement).toBeTruthy();
		expect(buttonElement).toHaveClass("my-class");
	});

	it("should render the children", () => {
		const props = createDefaultProps();
		props.children = "el texto";
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<Button {...props} />
			</ThemeProvider>,
		);

		expect(screen.getByText<HTMLElement>("el texto")).toBeInTheDocument();
	});

	it("should trigger the onClick action", () => {
		const props = createDefaultProps();
		props.buttonStyle = "lineInverse";
		const handleOnClickMock = props.onClick as jest.MockedFunction<(e: React.MouseEvent<HTMLButtonElement>) => void>;
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<Button {...props} />
			</ThemeProvider>,
		);

		const buttonElement = screen.getByTestId("button-line-inverse");
		expect(buttonElement).toBeTruthy();
		fireEvent.click(buttonElement);
		expect(handleOnClickMock).toHaveBeenCalled();
	});

	it("should not trigger the onClick action if the button is disabled", () => {
		const props = createDefaultProps();
		props.buttonStyle = "lineInverse";
		props.disabled = true;
		const handleOnClickMock = props.onClick as jest.MockedFunction<(e: React.MouseEvent<HTMLButtonElement>) => void>;
		render(
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<Button {...props} />
			</ThemeProvider>,
		);

		const buttonElement = screen.getByTestId("button-line-inverse");
		expect(buttonElement).toBeTruthy();
		expect(buttonElement).toBeDisabled();
		fireEvent.click(buttonElement);
		expect(handleOnClickMock).not.toHaveBeenCalled();
	});
});
