import parseQueryString from "@insite/client-framework/Common/Utilities/parseQueryString";
import setPageMetadata from "@insite/client-framework/Common/Utilities/setPageMetadata";
import Zone from "@insite/client-framework/Components/Zone";
import ApplicationState from "@insite/client-framework/Store/ApplicationState";
import setBreadcrumbs from "@insite/client-framework/Store/Components/Breadcrumbs/Handlers/SetBreadcrumbs";
import { getSettingsCollection } from "@insite/client-framework/Store/Context/ContextSelectors";
import {
    DealerStateContext,
    getDealerState,
    getDealerStateByPath,
} from "@insite/client-framework/Store/Data/Dealers/DealersSelectors";
import {
    getAlternateLanguageUrls,
    getCanonicalUrlByPath,
    getCurrentPage,
    getLocation,
} from "@insite/client-framework/Store/Data/Pages/PageSelectors";
import { getHomePageUrl, getPageLinkByPageType } from "@insite/client-framework/Store/Links/LinksSelectors";
import ensureDealerLoaded from "@insite/client-framework/Store/Data/Dealers/Handlers/EnsureDealerLoaded";
import PageModule from "@insite/client-framework/Types/PageModule";
import PageProps from "@insite/client-framework/Types/PageProps";
import { generateLinksFrom } from "@insite/content-library/Components/PageBreadcrumbs";
import { LinkProps } from "@insite/mobius/Link";
import Page from "@insite/mobius/Page";
import cloneDeep from "lodash/cloneDeep";
import React from "react";
import { connect, ResolveThunks } from "react-redux";
import { getContentByVersionPath } from "@insite/client-framework/Services/ContentService";

const mapStateToProps = (state: ApplicationState) => {
    const location = getLocation(state);
    const parsedQuery = parseQueryString<{ id?: string; invite?: string }>(location.search);
    const id = parsedQuery.id;
    const homePageUrl = getHomePageUrl(state);
    const page = getCurrentPage(state);
    const dealerPath =
        (location.pathname === getContentByVersionPath
            ? parseQueryString<{ dealerPath: string }>(location.search).dealerPath
            : "") || (location.pathname.toLowerCase().startsWith("/content/") ? "" : location.pathname);

    return {
        state,
        homePageUrl,
        dealerId: id,
        dealerState: id ? getDealerState(state, id) : getDealerStateByPath(state, dealerPath),
        links: state.links,
        dealerDetailsPageLink: getPageLinkByPageType(state, "DealerDetailsPage"),
        nodeId: page.nodeId,
        breadcrumbLinks: state.components.breadcrumbs.links,
        websiteName: state.context.website.name,
        dealerPath: location.pathname,
        websiteSettings: getSettingsCollection(state).websiteSettings,
        alternateLanguageUrls: getAlternateLanguageUrls(state, page.id),
        canonicalPath: getCanonicalUrlByPath(state, location.pathname),
    };
};

const mapDispatchToProps = {
    setBreadcrumbs,
    ensureDealerLoaded,
};

type Props = PageProps & ReturnType<typeof mapStateToProps> & ResolveThunks<typeof mapDispatchToProps>;

interface State {
    metadataUpdatedForId?: string;
}

class DealerDetailsPage extends React.Component<Props, State> {
    constructor(props: Props) {
        super(props);

        this.state = {};
    }

    UNSAFE_componentWillMount(): void {
        const { state, dealerId, breadcrumbLinks, dealerState, dealerPath, ensureDealerLoaded } = this.props;

        const shouldLoadDealer =
            !dealerState.value && !dealerState.isLoading && !state.data.dealers.pathNotFound[dealerPath];
        const inCMS = dealerPath.toLowerCase().startsWith("/content/page/");
        if (shouldLoadDealer && !inCMS) {
            ensureDealerLoaded({ dealerId, dealerPath });
        }

        if (!dealerState.value) {
            this.setMetadata(false);
        }
        if (!breadcrumbLinks && dealerState.value) {
            this.setPageBreadcrumbs();
        }
    }

    componentDidUpdate(prevProps: Props) {
        const { state, dealerId, dealerState, dealerPath, ensureDealerLoaded } = this.props;

        if (prevProps && dealerState.value && dealerState.value?.id !== prevProps.dealerState?.value?.id) {
            this.setPageBreadcrumbs();
        }

        if (dealerState.value && dealerState.value.id !== this.state.metadataUpdatedForId) {
            this.setMetadata(true);
        }

        const shouldLoadDealer =
            !dealerState.value && !dealerState.isLoading && !state.data.dealers.pathNotFound[dealerPath];
        const inCMS = dealerPath.toLowerCase().startsWith("/content/page/");
        if (shouldLoadDealer && !inCMS) {
            ensureDealerLoaded({ dealerId, dealerPath });
        }
    }

    componentWillUnmount() {
        this.props.setBreadcrumbs({ links: undefined });
    }

    setMetadata(isUpdate: boolean) {
        const {
            dealerState: { value: dealer },
            websiteName,
            dealerPath,
            websiteSettings,
            alternateLanguageUrls,
            canonicalPath,
        } = this.props;
        if (!dealer) {
            return;
        }

        setPageMetadata(
            {
                currentPath: dealerPath,
                title: dealer.name,
                websiteName,
                alternateLanguageUrls,
                canonicalPath,
            },
            websiteSettings,
        );

        if (isUpdate) {
            this.setState({
                metadataUpdatedForId: dealer.id,
            });
        }
    }

    setPageBreadcrumbs() {
        const { dealerState, links, nodeId, dealerDetailsPageLink, homePageUrl, setBreadcrumbs } = this.props;

        const breadcrumbs = generateLinksFrom(links, nodeId, homePageUrl);
        const updatedBreadcrumbs = cloneDeep(breadcrumbs) as LinkProps[];
        updatedBreadcrumbs.forEach(link => {
            link.children = link.children === dealerDetailsPageLink?.title ? dealerState.value!.name! : link.children;
        });
        setBreadcrumbs({ links: updatedBreadcrumbs });
    }

    render() {
        return (
            <Page>
                <DealerStateContext.Provider value={this.props.dealerState}>
                    <Zone contentId={this.props.id} zoneName="Content" />
                </DealerStateContext.Provider>
            </Page>
        );
    }
}

const pageModule: PageModule = {
    component: connect(mapStateToProps, mapDispatchToProps)(DealerDetailsPage),
    definition: {
        hasEditableUrlSegment: true,
        hasEditableTitle: true,
        pageType: "System",
    },
};

export default pageModule;

/**
 * @deprecated Use string literal "DealerDetailsPage" instead of this constant.
 */
export const DealerDetailsPageContext = "DealerDetailsPage";
