import axios from "axios";
import { Router } from "react-router-dom";

import configureStore from "redux-mock-store";
import thunk from "redux-thunk";
import { ThemeProvider } from "styled-components";

import { parseTheme } from "@ax/helpers";
import Social from "@ax/modules/Settings/Social";
import history from "@ax/routes/history";
import globalTheme from "@ax/themes/theme.json";

import { act, cleanup, render, screen } from "../../../../../config/jest/test-utils";

jest.mock("axios");
const mockedAxios = axios as jest.MockedFunction<typeof axios>;

beforeEach(() => {
	mockedAxios.mockResolvedValue({ status: 200, data: {}, statusText: "OK", headers: {}, config: {} as any });
});

afterEach(cleanup);

const mockComponent = () => null;

const mockNavItems = [
	{ title: "Social", path: "/settings/social", component: mockComponent },
	{ title: "Other", path: "/settings/other", component: mockComponent },
];

const mockCurrentNavItem = { title: "Social", path: "/settings/social", component: mockComponent };

const createMockStore = (overrides = {}) => {
	const defaultStore = {
		app: { isSaving: false },
		social: {},
		sites: { currentSiteInfo: { id: 1 } },
		users: { currentPermissions: [] },
		...overrides,
	};
	const middlewares: any = [thunk];
	const mockStore = configureStore(middlewares);
	return mockStore(defaultStore);
};

describe("Social Settings Component", () => {
	it("should render the Social settings component", async () => {
		const store = createMockStore();

		await act(async () => {
			render(
				<Router history={history}>
					<ThemeProvider theme={parseTheme(globalTheme)}>
						<Social navItems={mockNavItems} currentNavItem={mockCurrentNavItem} />
					</ThemeProvider>
				</Router>,
				{ store },
			);
		});

		// Check that the title is rendered
		expect(screen.getByRole("heading", { name: "Social" })).toBeTruthy();
	});

	it("should render social fields from state", async () => {
		const store = createMockStore({
			social: {
				instagram: "https://instagram.com/user",
				twitter: "https://twitter.com/user",
			},
		});

		await act(async () => {
			render(
				<Router history={history}>
					<ThemeProvider theme={parseTheme(globalTheme)}>
						<Social navItems={mockNavItems} currentNavItem={mockCurrentNavItem} />
					</ThemeProvider>
				</Router>,
				{ store },
			);
		});

		expect(await screen.findByDisplayValue("https://instagram.com/user")).toBeTruthy();
		expect(screen.getByDisplayValue("https://twitter.com/user")).toBeTruthy();
	});

	it("should render hardcoded socials when they have values", async () => {
		const store = createMockStore({
			social: {
				instagram: "https://instagram.com/user",
				facebook: "",
			},
		});

		await act(async () => {
			render(
				<Router history={history}>
					<ThemeProvider theme={parseTheme(globalTheme)}>
						<Social navItems={mockNavItems} currentNavItem={mockCurrentNavItem} />
					</ThemeProvider>
				</Router>,
				{ store },
			);
		});

		// Check that fields with values from social state are rendered
		expect(screen.getByDisplayValue("https://instagram.com/user")).toBeTruthy();
	});

	it("should have Instagram field visible", async () => {
		const store = createMockStore({
			social: {
				instagram: "https://instagram.com/user",
			},
		});

		await act(async () => {
			render(
				<Router history={history}>
					<ThemeProvider theme={parseTheme(globalTheme)}>
						<Social navItems={mockNavItems} currentNavItem={mockCurrentNavItem} />
					</ThemeProvider>
				</Router>,
				{ store },
			);
		});

		// Verify Instagram field is rendered with correct value
		const instagramValue = screen.getByDisplayValue("https://instagram.com/user");
		expect(instagramValue).toBeTruthy();
	});

	it("should show button with correct state when form is not dirty", async () => {
		const store = createMockStore({
			social: {
				instagram: "https://instagram.com/user",
			},
		});

		await act(async () => {
			render(
				<Router history={history}>
					<ThemeProvider theme={parseTheme(globalTheme)}>
						<Social navItems={mockNavItems} currentNavItem={mockCurrentNavItem} />
					</ThemeProvider>
				</Router>,
				{ store },
			);
		});

		// Should have a button (the save button) that is disabled when not dirty
		const buttons = screen.getAllByRole("button");
		const saveButton = buttons.find((btn) => btn.textContent?.includes("Save"));
		expect(saveButton).toBeTruthy();
		expect(saveButton?.hasAttribute("disabled")).toBe(true);
	});

	it("should display saving state", async () => {
		const store = createMockStore({
			app: { isSaving: true },
		});

		await act(async () => {
			render(
				<Router history={history}>
					<ThemeProvider theme={parseTheme(globalTheme)}>
						<Social navItems={mockNavItems} currentNavItem={mockCurrentNavItem} />
					</ThemeProvider>
				</Router>,
				{ store },
			);
		});

		const saveButton = screen.getByRole("button", { name: /saving/i });
		expect(saveButton.textContent).toBe("Saving");
		expect(saveButton.hasAttribute("disabled")).toBe(true);
	});

	it("should render instance socials from config", async () => {
		const store = createMockStore({
			social: {
				customSocial: "https://example.com",
			},
		});

		await act(async () => {
			render(
				<Router history={history}>
					<ThemeProvider theme={parseTheme(globalTheme)}>
						<Social navItems={mockNavItems} currentNavItem={mockCurrentNavItem} />
					</ThemeProvider>
				</Router>,
				{ store },
			);
		});

		// The component should render without errors even if config.schemas.config.socials is empty
		expect(screen.getByRole("heading", { name: "Social" })).toBeTruthy();
	});

	it("should not duplicate socials between instance and hardcoded", async () => {
		const store = createMockStore({
			social: {
				instagram: "https://instagram.com/user",
			},
		});

		await act(async () => {
			render(
				<Router history={history}>
					<ThemeProvider theme={parseTheme(globalTheme)}>
						<Social navItems={mockNavItems} currentNavItem={mockCurrentNavItem} />
					</ThemeProvider>
				</Router>,
				{ store },
			);
		});

		// Instagram should only appear once (from instance or hardcoded, not both)
		const instagramLabels = screen.queryAllByText(/instagram/i);
		expect(instagramLabels.length).toBeGreaterThanOrEqual(1);
	});

	it("should handle nav menu clicks with dispatch", async () => {
		const store = createMockStore();

		await act(async () => {
			render(
				<Router history={history}>
					<ThemeProvider theme={parseTheme(globalTheme)}>
						<Social navItems={mockNavItems} currentNavItem={mockCurrentNavItem} />
					</ThemeProvider>
				</Router>,
				{ store },
			);
		});

		// Component should render the Nav component which handles menu clicks
		expect(screen.getByRole("heading", { name: "Social" })).toBeTruthy();
	});
});
