import React from "react";
import axios from "axios";
import "@testing-library/jest-dom";
import configureStore from "redux-mock-store";
import { ThemeProvider } from "styled-components";
import { mock } from "jest-mock-extended";

import { render, cleanup, screen, act, fireEvent } from "../../../../../config/jest/test-utils";
import {
	pageResponse,
	pageResponseWithTabs,
	sitePagesResponse,
	structuredDataResponse,
} from "../../../../__mocks__/mockedAxios";

import { parseTheme } from "@ax/helpers";
import UrlField, { IUrlFieldProps } from "@ax/components/Fields/UrlField/index";
import globalTheme from "@ax/themes/theme.json";

afterEach(() => {
	cleanup();
	jest.resetAllMocks();
});

const defaultProps = mock<IUrlFieldProps>();

const globalLang = {
	id: 19,
	locale: "en",
	language: "English",
	label: "EN",
	isDefault: true,
};

const defaultSite = {
	id: 80,
	name: "DEMO SITE",
	theme: "default-theme",
	author: 2,
	pages: [3654, 3729, 3997, 4014, 4074],
	published: "2021-11-03T10:10:17.000Z",
	modified: "2022-05-23T11:49:42.000Z",
	languageSites: [144],
	deleted: 0,
	thumbnail: "http://images.dev.griddo.io/macbeth-palau-de-les-arts-opera-valencia-5x2-1_1",
	timezone: "Pacific/Pago_Pago",
	favicon: "http://images.dev.griddo.io/griddo-site-thumbnail-ec2ab0ba-9424-4424-8f60-222ec746902d_4",
	hash: null,
	bigAvatar: "http://images.dev.griddo.io/griddo-site-thumbnail-ec2ab0ba-9424-4424-8f60-222ec746902d_6",
	smallAvatar: "http://images.dev.griddo.io/griddo-site-thumbnail-ec2ab0ba-9424-4424-8f60-222ec746902d_5",
	rendering: false,
	slug: "/demo-site",
	isPublished: true,
	renderingHours: 0,
	shouldBeUpdated: false,
	updated: true,
	navigationModules: null,
	home: "//cx.dev.griddo.io/pre-griddo/demo",
};

const sitesMock = {
	currentSiteInfo: null,
	sites: [defaultSite],
	currentSiteName: null,
	currentSitePages: [],
	sitesByLang: [],
	currentFilter: "unique-pages",
	totalItems: 0,
	currentSiteLanguages: [],
	savedSiteInfo: null,
	currentSiteErrorPages: [],
};

const appMock = {
	isRehydrated: true,
	isLoading: true,
	isSaving: false,
	error: {
		code: undefined,
		text: "",
	},
	user: {
		email: "",
	},
	token: "",
	isLoggingIn: false,
	lang: {
		locale: "en-GB",
		id: 4,
	},
	globalLangs: [globalLang],
	globalSettings: {
		cloudinaryName: "",
		globalLogoBig: "",
		globalLogoMini: "",
		siteLogoBig: "",
		siteLogoMini: "",
		welcomeText1: "",
		welcomeText2: "",
	},
};

const initialStore = {
	sites: sitesMock,
	app: appMock,
};

const middlewares: any = [];
const mockStore = configureStore(middlewares);

const store = mockStore(initialStore);

jest.mock("axios");
const mockedAxios = axios as jest.MockedFunction<typeof axios>;
const mockApiCalls = () =>
	mockedAxios.mockImplementation((request: any) => {
		switch (request.url) {
			case "undefined/page/4111":
				return Promise.resolve(pageResponse);
			case "undefined/site/80/structured_data":
				return Promise.resolve(structuredDataResponse);
			case "undefined/site/80/pages?deleted=false&page=1&itemsPerPage=50&filterStructuredData=all&format=list":
				return Promise.resolve(sitePagesResponse);
			default:
				return Promise.reject(new Error("not found"));
		}
	});

describe("UrlField component rendering", () => {
	test("should render the component UrlField", async () => {
		const initialState = { ...initialStore, ...defaultProps };

		pageResponse.data.follow = false;

		mockApiCalls();

		await act(async () => {
			render(
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<UrlField {...initialState} />
				</ThemeProvider>,
				{ store },
			);
		});

		expect(screen.getByTestId("url-field-wrapper")).toBeTruthy();
	});

	test("should render the component UrlField with API response fail", async () => {
		defaultProps.value = {
			href: null,
			linkTo: 4111,
			linkToURL: "//cx.dev.griddo.io/pre-griddo/gonzalo-h/new-page/",
			title: "New Page",
			anchor: "mega-anchor",
		};
		const initialState = { ...initialStore, ...defaultProps };

		const responseFail = {
			data: null,
			status: 400,
			statusText: "Fail",
			headers: {},
			config: {},
		};

		mockedAxios.mockImplementation((request: any) => {
			switch (request.url) {
				case "undefined/page/4111":
					return Promise.resolve(responseFail);
				case "undefined/site/80/structured_data":
					return Promise.resolve(structuredDataResponse);
				case "undefined/site/80/pages?deleted=false&page=1&itemsPerPage=50&filterStructuredData=all&format=list":
					return Promise.resolve(responseFail);
				default:
					return Promise.reject(new Error("not found"));
			}
		});

		await act(async () => {
			render(
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<UrlField {...initialState} />
				</ThemeProvider>,
				{ store },
			);
		});

		expect(screen.getByTestId("url-field-wrapper")).toBeTruthy();
	});

	test("should render the component UrlField with API response Ok", async () => {
		defaultProps.value = {
			href: null,
			linkTo: 4111,
			linkToURL: "//cx.dev.griddo.io/pre-griddo/gonzalo-h/new-page/",
			anchor: "mega-anchor",
		};
		const onChange = jest.fn();

		const initialState = { ...initialStore, ...defaultProps };

		const handlePanel = jest.fn();

		mockApiCalls();

		const Component = (
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<UrlField {...initialState} handlePanel={handlePanel} showAdvanced onChange={onChange} />
			</ThemeProvider>
		);

		await act(async () => {
			render(Component, { store });
		});

		expect(screen.getByText("mega-anchor")).toBeTruthy();
	});

	test("should render the select with tabs", async () => {
		defaultProps.value = {
			href: null,
			linkTo: 4111,
			linkToURL: "//cx.dev.griddo.io/pre-griddo/gonzalo-h/new-page/",
		};
		const onChange = jest.fn();
		const handlePanel = jest.fn();

		const initialState = { ...initialStore, ...defaultProps };

		mockedAxios.mockImplementation((request: any) => {
			switch (request.url) {
				case "undefined/page/4111":
					return Promise.resolve(pageResponseWithTabs);
				case "undefined/site/80/structured_data":
					return Promise.resolve(structuredDataResponse);
				case "undefined/site/80/pages?deleted=false&page=1&itemsPerPage=50&filterStructuredData=all&format=list":
					return Promise.resolve(sitePagesResponse);
				default:
					return Promise.reject(new Error("not found"));
			}
		});

		const Component = (
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<UrlField {...initialState} handlePanel={handlePanel} showAdvanced onChange={onChange} />
			</ThemeProvider>
		);

		await act(async () => {
			render(Component, { store });
		});

		expect(screen.getAllByTestId("select-component")).toBeTruthy();
	});

	test("should render the select with tabs and subSlug", async () => {
		defaultProps.value = {
			href: null,
			linkTo: 4111,
			linkToURL: "//cx.dev.griddo.io/pre-griddo/gonzalo-h/new-page/",
			subSlug: "sub-slug",
			anchor: "anchor",
		};
		const onChange = jest.fn();
		const handlePanel = jest.fn();

		const initialState = { ...initialStore, ...defaultProps };

		mockedAxios.mockImplementation((request: any) => {
			switch (request.url) {
				case "undefined/page/4111":
					return Promise.resolve(pageResponseWithTabs);
				case "undefined/site/80/structured_data":
					return Promise.resolve(structuredDataResponse);
				case "undefined/site/80/pages?deleted=false&page=1&itemsPerPage=50&filterStructuredData=all&format=list":
					return Promise.resolve(sitePagesResponse);
				default:
					return Promise.reject(new Error("not found"));
			}
		});

		const Component = (
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<UrlField {...initialState} handlePanel={handlePanel} showAdvanced onChange={onChange} />
			</ThemeProvider>
		);

		await act(async () => {
			render(Component, { store });
		});

		// Open FloatingPanel first
		const pageField = screen.getByTestId("page-field");
		await act(async () => {
			fireEvent.click(pageField);
		});

		const selectComponents = screen.getAllByTestId("select-component");

		await act(async () => {
			selectComponents[2].click();
		});

		expect(selectComponents).toBeTruthy();
	});
});

describe("onChange events", () => {
	test("should render the component UrlField with default values", async () => {
		defaultProps.value = null;
		const initialState = { ...initialStore, ...defaultProps };

		const onChange = jest.fn();

		const responseFail = {
			data: null,
			status: 400,
			statusText: "Fail",
			headers: {},
			config: {},
		};

		mockedAxios.mockImplementation((request: any) => {
			switch (request.url) {
				case "undefined/page/4111":
					return Promise.resolve(responseFail);
				case "undefined/site/80/structured_data":
					return Promise.resolve(structuredDataResponse);
				case "undefined/site/80/pages?deleted=false&page=1&itemsPerPage=50&filterStructuredData=all&format=list":
					return Promise.resolve(responseFail);
				default:
					return Promise.reject(new Error("not found"));
			}
		});

		await act(async () => {
			render(
				<ThemeProvider theme={parseTheme(globalTheme)}>
					<UrlField {...initialState} showAdvanced onChange={onChange} />
				</ThemeProvider>,
				{ store },
			);
		});

		const inputComponents = screen.getAllByTestId("input-component");

		await act(async () => {
			fireEvent.change(inputComponents[0], { target: { value: "eooo" } });
			fireEvent.change(inputComponents[1], { target: { value: "kaiso" } });
		});

		expect(screen.getAllByRole("textbox")[0]).toHaveValue("eooo");
		expect(screen.getAllByRole("textbox")[1]).toHaveValue("kaiso");
	});
});

describe("onClick events", () => {
	test("should call handleValidation", async () => {
		defaultProps.value = {
			href: null,
			linkTo: 4111,
			linkToURL: "//cx.dev.griddo.io/pre-griddo/gonzalo-h/new-page/",
			title: "New Page",
			anchor: "mega-anchor",
		};

		const onChange = jest.fn();
		const handleValidation = jest.fn();

		const initialState = { ...initialStore, ...defaultProps };

		const handlePanel = jest.fn();

		mockApiCalls();

		const Component = (
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<UrlField
					{...initialState}
					handlePanel={handlePanel}
					showAdvanced
					onChange={onChange}
					handleValidation={handleValidation}
				/>
			</ThemeProvider>
		);

		await act(async () => {
			render(Component, { store });
		});

		// Open FloatingPanel first
		const pageField = screen.getByTestId("page-field");
		await act(async () => {
			fireEvent.click(pageField);
		});

		await act(async () => {
			const selectionListItem = screen.getAllByTestId("selection-list-item");
			selectionListItem[0].click();

			const inputComponents = screen.getAllByTestId("input-component");
			fireEvent.change(inputComponents[0], { value: "foo" });
		});

		expect(handleValidation).toBeCalledTimes(1);
	});

	test("should call handleValidation and onChange", async () => {
		defaultProps.value = {
			href: null,
			linkTo: 4111,
			linkToURL: "//cx.dev.griddo.io/pre-griddo/gonzalo-h/new-page/",
			title: "New Page",
			anchor: "mega-anchor",
		};

		const onChange = jest.fn();
		const handleValidation = jest.fn();
		const handlePanel = jest.fn();
		const resetValidation = jest.fn();

		const initialState = { ...initialStore, ...defaultProps };

		mockApiCalls();

		const Component = (
			<ThemeProvider theme={parseTheme(globalTheme)}>
				<UrlField
					{...initialState}
					handlePanel={handlePanel}
					showAdvanced
					onChange={onChange}
					handleValidation={handleValidation}
					resetValidation={resetValidation}
				/>
			</ThemeProvider>
		);

		await act(async () => {
			render(Component, { store });
		});

		const checkFieldInputs = screen.getAllByTestId("check-field-input");
		const pageField = screen.getByTestId("page-field");

		// Open FloatingPanel first
		await act(async () => {
			fireEvent.click(pageField);
		});

		const selectionListItem = screen.getAllByTestId("selection-list-item");

		await act(async () => {
			selectionListItem[0].click();
			fireEvent.click(checkFieldInputs[0]);
			fireEvent.click(checkFieldInputs[1]);
			fireEvent.click(pageField);
		});

		expect(handleValidation).toBeCalledTimes(1);
		expect(onChange).toBeCalledTimes(3);
	});
});
