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

import ReferenceField, { IReferenceFieldProps } from "@ax/components/Fields/ReferenceField/index";
import globalTheme from "@ax/themes/theme.json";

import { render, cleanup, screen, act, fireEvent } from "../../../../../config/jest/test-utils";
import {
	articlesDistributorResponse,
	storiesDistributorResponse,
	articlesDataTitlesResponse,
	storiesDataTitlesResponse,
	structuredDataContentsResponse,
	emptyArticlesDistributorResponse,
} from "../../../../__mocks__/axios/ReferenceField";
import { structuredDataMock, sitesMock, appMock } from "../../../../__mocks__/store/ReferenceField";

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

const defaultProps = mock<IReferenceFieldProps>();
defaultProps.value = { sources: [{ structuredData: "ARTICLES" }] };
defaultProps.sources = [{ structuredData: "ARTICLES" }];

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

const mockStore = configureStore();
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/structured_data/titles/ARTICLES":
				return Promise.resolve(articlesDataTitlesResponse);
			case "undefined/structured_data/titles/STORIES":
				return Promise.resolve(storiesDataTitlesResponse);
			case "undefined/site/85/distributor":
				return Promise.resolve(articlesDistributorResponse);
			case "undefined/site/85/structured_data_contents/ARTICLES?page=1&itemsPerPage=50&pagination=true&deleted=false&includeDraft=false":
				return Promise.resolve(structuredDataContentsResponse);
			default:
				return Promise.reject(new Error("not found"));
		}
	});

describe("ReferenceField component rendering", () => {
	test("should render the component ReferenceField", async () => {
		defaultProps.value = {
			order: "alpha-DESC",
		};
		defaultProps.selectionType = ["auto"];
		const onChange = jest.fn();
		const initialState = { ...initialStore, ...defaultProps };

		mockApiCalls();

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

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

	test("should render the component ReferenceField with API response fail", async () => {
		defaultProps.value = {
			order: "other-DESC",
		};
		defaultProps.selectionType = undefined;
		const initialState = { ...initialStore, ...defaultProps };

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

		mockedAxios.mockImplementation((request: any) => {
			switch (request.url) {
				case "undefined/structured_data/titles/ARTICLES":
					return Promise.resolve(responseFail);
				default:
					return Promise.reject(new Error("not found"));
			}
		});

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

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

	test("should render the component ReferenceField with value undefined", async () => {
		defaultProps.value = undefined;
		const initialState = { ...initialStore, ...defaultProps };

		mockApiCalls();

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

		expect(screen.getByTestId("auto-data-wrapper")).toBeTruthy();
	});

	test("should render the component ReferenceField with fixed is empty", async () => {
		defaultProps.sources = [{ structuredData: "ARTICLES" }];
		defaultProps.value = {
			mode: "manual",
			fixed: [],
		};
		const initialState = { ...initialStore, ...defaultProps };
		const onChange = jest.fn();

		mockedAxios.mockImplementation((request: any) => {
			switch (request.url) {
				case "undefined/structured_data/titles/ARTICLES":
					return Promise.resolve(articlesDataTitlesResponse);
				case "undefined/structured_data/titles/STORIES":
					return Promise.resolve(storiesDataTitlesResponse);
				case "undefined/site/85/distributor":
					return Promise.resolve(emptyArticlesDistributorResponse);
				case "undefined/site/85/structured_data_contents/ARTICLES?page=1&itemsPerPage=50&pagination=true&deleted=false&includeDraft=false":
					return Promise.resolve(structuredDataContentsResponse);
				default:
					return Promise.reject(new Error("not found"));
			}
		});

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

		const { rerender } = render(Component, { store });

		await act(async () => {
			rerender(Component);
		});

		expect(screen.queryAllByTestId("reference-field-item")).toHaveLength(0);
	});
});

describe("onChange events", () => {
	test("should apply change in AutoPanel", async () => {
		defaultProps.sources = [{ structuredData: "STORIES" }];
		defaultProps.value = {
			sources: [
				{
					structuredData: "STORIES",
					filters: [
						{
							id: 4418,
							label: "Story Type 1",
						},
						{
							id: 4419,
							label: "Story Type 2",
						},
					],
					globalOperator: "AND",
					filterOperator: "ANY",
				},
			],
			quantity: 1,
		};
		const initialState = { ...initialStore, ...defaultProps };
		const onChange = jest.fn();

		mockedAxios.mockImplementation((request: any) => {
			switch (request.url) {
				case "undefined/structured_data/titles/ARTICLES":
					return Promise.resolve(articlesDataTitlesResponse);
				case "undefined/structured_data/titles/STORIES":
					return Promise.resolve(storiesDataTitlesResponse);
				case "undefined/site/85/distributor":
					return Promise.resolve(storiesDistributorResponse);
				default:
					return Promise.reject(new Error("not found"));
			}
		});

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

		const { rerender } = render(Component, { store });

		let iconActionComponents = screen.getAllByTestId("icon-action-component");

		await act(async () => {
			fireEvent.click(iconActionComponents[0]);
		});

		await act(async () => {
			rerender(Component);
		});

		iconActionComponents = screen.getAllByTestId("icon-action-component");

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

		const radioFieldInputs = screen.getAllByTestId("radio-field-input");
		await act(async () => {
			fireEvent.click(radioFieldInputs[1]);
			fireEvent.click(radioFieldInputs[4]);
		});

		const arrowUp = screen.getByTestId("arrow-up");
		await act(async () => {
			fireEvent.click(arrowUp);
		});

		expect(screen.getByTestId("auto-panel-wrapper")).toBeTruthy();
		expect(screen.getByTestId("input")).toHaveValue(2);

		await act(async () => {
			fireEvent.click(radioFieldInputs[5]);

			const buttonDefault = screen.getByTestId("button-default");
			fireEvent.click(buttonDefault);
		});

		expect(onChange).toHaveBeenCalledTimes(1);
	});

	test("should add item in manual mode", async () => {
		defaultProps.sources = [{ structuredData: "ARTICLES" }];
		defaultProps.value = {
			mode: "manual",
			fixed: [4492, 4493],
		};
		const initialState = { ...initialStore, ...defaultProps };
		const onChange = jest.fn();

		mockApiCalls();

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

		const { rerender } = render(Component, { store });

		await act(async () => {
			rerender(Component);
		});

		let referenceFieldItems = screen.getAllByTestId("reference-field-item");
		expect(referenceFieldItems.length).toBe(2);

		const iconActionComponents = screen.getAllByTestId("icon-action-component");

		await act(async () => {
			fireEvent.click(iconActionComponents[0]);
		});

		await act(async () => {
			rerender(Component);
		});

		const manualPanelItem = screen.getAllByTestId("manual-panel-item");
		expect(manualPanelItem.length).toBe(8);

		await act(async () => {
			fireEvent.click(manualPanelItem[4]);
			fireEvent.click(screen.getByTestId("button-default"));
		});

		await act(async () => {
			rerender(Component);
		});

		referenceFieldItems = screen.getAllByTestId("reference-field-item");
		expect(referenceFieldItems.length).toBe(3);
	});

	test("should remove item in manual mode", async () => {
		defaultProps.sources = [{ structuredData: "ARTICLES" }];
		defaultProps.value = {
			mode: "manual",
			fixed: [4492, 4493],
		};
		defaultProps.maxItems = 3;
		const initialState = { ...initialStore, ...defaultProps };
		const onChange = jest.fn();

		mockApiCalls();

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

		const { rerender } = render(Component, { store });

		await act(async () => {
			rerender(Component);
		});

		let referenceFieldItems = screen.getAllByTestId("reference-field-item");
		expect(referenceFieldItems.length).toBe(2);

		const iconActionComponents = screen.getAllByTestId("icon-action-component");

		await act(async () => {
			fireEvent.click(iconActionComponents[0]);
		});

		await act(async () => {
			rerender(Component);
		});

		const manualPanelItem = screen.getAllByTestId("manual-panel-item");
		expect(manualPanelItem.length).toBe(8);

		await act(async () => {
			fireEvent.click(manualPanelItem[0]);
			fireEvent.click(manualPanelItem[6]);
			fireEvent.click(screen.getByTestId("button-default"));
		});

		await act(async () => {
			rerender(Component);
		});

		referenceFieldItems = screen.getAllByTestId("reference-field-item");
		expect(referenceFieldItems.length).toBe(1);
	});

	test("should delete filter tags", async () => {
		defaultProps.sources = [{ structuredData: "STORIES" }];
		defaultProps.value = {
			sources: [
				{
					structuredData: "STORIES",
					filters: [
						{
							id: 4418,
							label: "Story Type 1",
						},
						{
							id: 4419,
							label: "Story Type 2",
						},
					],
					globalOperator: "AND",
					filterOperator: "ANY",
				},
			],
		};
		const initialState = { ...initialStore, ...defaultProps };
		const onChange = jest.fn();

		mockedAxios.mockImplementation((request: any) => {
			switch (request.url) {
				case "undefined/structured_data/titles/ARTICLES":
					return Promise.resolve(articlesDataTitlesResponse);
				case "undefined/structured_data/titles/STORIES":
					return Promise.resolve(storiesDataTitlesResponse);
				case "undefined/site/85/distributor":
					return Promise.resolve(storiesDistributorResponse);
				default:
					return Promise.reject(new Error("not found"));
			}
		});

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

		const { rerender } = render(Component, { store });

		const iconActionComponents = screen.getAllByTestId("icon-action-component");

		await act(async () => {
			fireEvent.click(iconActionComponents[0]);
		});

		await act(async () => {
			rerender(Component);
		});

		let tagComponent = screen.getAllByTestId("delete-icon-wrapper");

		expect(tagComponent.length).toBe(2);

		await act(async () => {
			fireEvent.click(tagComponent[1]);
		});

		await act(async () => {
			rerender(Component);
		});

		tagComponent = screen.getAllByTestId("delete-icon-wrapper");

		expect(tagComponent.length).toBe(1);
	});

	/*test("should reorder items", async () => {
    defaultProps.source = ["ARTICLES"];
    defaultProps.value = {
      mode: "manual",
      fixed: [4492, 4493],
    };
    const initialState = { ...initialStore, ...defaultProps };
    const onChange = jest.fn();

  //   mockApiCalls();

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

  //   const { rerender } = render(Component, { store });

  //   await act(async () => {
  //     rerender(Component);
  //   });

    const referenceFieldItems = screen.getAllByTestId("reference-field-item");
    expect(referenceFieldItems[0]).toHaveTextContent("Article 02");

    const droppable = screen.getByTestId("droppable");
    expect(droppable).toBeTruthy();

    fireEvent.dragStart(referenceFieldItems[0]);
    fireEvent.dragEnter(droppable);
    fireEvent.dragOver(droppable);
    fireEvent.drop(droppable);
  });

  test("should render the drag handle if list length is greater than two", async () => {
    defaultProps.source = ["ARTICLES"];
    defaultProps.value = {
      mode: "manual",
      fixed: [4492, 4493],
    };
    const initialState = { ...initialStore, ...defaultProps };
    const onChange = jest.fn();

    mockApiCalls();

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

    const { rerender } = render(Component, { store });

    await act(async () => {
      rerender(Component);
    });

    const referenceFieldItems = screen.getAllByTestId("reference-field-item");
    expect(referenceFieldItems.length).toBe(2);
    const handleWrappers = screen.getAllByTestId("handle-wrapper");
    expect(handleWrappers.length).toEqual(2);
  });

  test("should delete items", async () => {
    defaultProps.source = ["ARTICLES"];
    defaultProps.value = {
      mode: "manual",
      fixed: [4492, 4493],
    };
    const initialState = { ...initialStore, ...defaultProps };
    const onChange = jest.fn();

    mockApiCalls();

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

    const { rerender } = render(Component, { store });

    await act(async () => {
      rerender(Component);
    });
    let referenceFieldItems = screen.getAllByTestId("reference-field-item");
    expect(referenceFieldItems.length).toBe(2);

    const iconActionComponents = screen.getAllByTestId("icon-action-component");

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

    await act(async () => {
      rerender(Component);
    });

    const actionMenuItem = screen.getByTestId("action-menu-item");
    await act(async () => {
      fireEvent.click(actionMenuItem);
    });

    //   await act(async () => {
    //     rerender(Component);
    //   });

    const referenceFieldItems = screen.getAllByTestId("reference-field-item");
    expect(referenceFieldItems[0]).toHaveTextContent("Article 02");

    const droppable = screen.getByTestId("droppable");
    expect(droppable).toBeTruthy();

    fireEvent.dragStart(referenceFieldItems[0]);
    fireEvent.dragEnter(droppable);
    fireEvent.dragOver(droppable);
    fireEvent.drop(droppable);
  });

  test("should render the drag handle if list length is greater than two", async () => {
    defaultProps.source = ["ARTICLES"];
    defaultProps.value = {
      mode: "manual",
      fixed: [4492, 4493],
    };
    const initialState = { ...initialStore, ...defaultProps };
    const onChange = jest.fn();

    mockApiCalls();

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

    const { rerender } = render(Component, { store });

    await act(async () => {
      rerender(Component);
    });

    const referenceFieldItems = screen.getAllByTestId("reference-field-item");
    expect(referenceFieldItems.length).toBe(2);
    const handleWrappers = screen.getAllByTestId("handle-wrapper");
    expect(handleWrappers.length).toEqual(2);
  });

  test("should hide the drag handle if list length is lower than two", async () => {
    defaultProps.source = ["ARTICLES"];
    defaultProps.value = {
      mode: "manual",
      fixed: [],
    };
    const initialState = { ...initialStore, ...defaultProps };
    const onChange = jest.fn();

    mockApiCalls();

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

    const { rerender } = render(Component, { store });

    await act(async () => {
      rerender(Component);
    });
    let referenceFieldItems = screen.getAllByTestId("reference-field-item");
    expect(referenceFieldItems.length).toBe(2);

    const iconActionComponents = screen.getAllByTestId("icon-action-component");

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

    await act(async () => {
      rerender(Component);
    });

    const actionMenuItem = screen.getByTestId("action-menu-item");
    await act(async () => {
      fireEvent.click(actionMenuItem);
    });

    //   await act(async () => {
    //     rerender(Component);
    //   });

    referenceFieldItems = screen.getAllByTestId("reference-field-item");
    expect(referenceFieldItems[0]).toHaveTextContent("Article 02");
  });*/
});
