import React, { useCallback, useEffect, useState } from "react";
import { Helmet, HelmetProvider } from "react-helmet-async";

import "./App.css";

import {
    FormWidgetEnv,
    FormWidgetConfig,
    parseWidgetEnv,
    FormWidgetTheme,
    WidgetStylesheet,
} from "@xapp/form-widget";

import { LoadingSpinner } from "./components/LoadingSpinner";
import { invertColor } from "./utils/color";
import { ContactPage } from "./ContactPage";
import { getAllTrackingParameters } from "./utils/tracking";
import { initMetaPixel, trackMetaPixelEvent } from "./utils/metaPixel";
import { getPartnerDetailsAsync, PartnerDetails } from "./utils/partnerDetails";
import { buildConnection } from "./utils/connection";

function App() {
    const [env, setEnv] = useState<FormWidgetEnv>();
    const [config, setConfig] = useState<FormWidgetConfig>();
    const [theme, setTheme] = useState<FormWidgetTheme>();
    const [partnerDetails, setPartnerDetails] = useState<PartnerDetails>();

    const [loading, setLoading] = useState<boolean>(true);
    const [disablePoweredBy, setDisablePoweredBy] = useState<boolean>(false);
    const [poweredByMessage, setPoweredByMessage] = useState<string>();
    const [poweredByUrl, setPoweredByUrl] = useState<string>();

    const [error, setError] = useState<Error>();

    // Stable reference so it doesn't churn FormWidget's submit-handler memoization.
    // The Lead event carries no PII — just a conversion signal. The eventId (a
    // random id shared with the server-side CAPI event) lets Meta dedupe the two.
    const handleSubmit = useCallback((eventId?: string) => {
        trackMetaPixelEvent("Lead", undefined, eventId);
    }, []);

    useEffect(() => {
        const pathname = window.location.pathname;
        const parameters = pathname.split("/");

        const urlLoc = new URL(window.location.href);

        // using params makes it easier to test in VSC with GoLive or serve
        const key = parameters[1] || urlLoc.searchParams.get("key");

        // these are optional
        const businessName = urlLoc.searchParams.get("businessName") || undefined;
        const businessAddress = urlLoc.searchParams.get("businessAddress") || undefined;
        const businessLogoUrl = urlLoc.searchParams.get("businessLogoUrl") || undefined;
        const businessWebsite = urlLoc.searchParams.get("businessWebsite") || undefined;
        const chatWidgetKey = urlLoc.searchParams.get("chatWidgetKey") || undefined;
        const partnerId = urlLoc.searchParams.get("partnerId") || undefined;

        const disablePoweredBy = urlLoc.searchParams.get("disablePoweredBy") === "true";
        const poweredByMessage = urlLoc.searchParams.get("poweredByMessage") || undefined;
        const poweredByUrl = urlLoc.searchParams.get("poweredByUrl") || undefined;

        // These query parameters we store locally so that the widgets can use them
        const service = urlLoc.searchParams.get("service");
        if (service) {
            localStorage.setItem("xa_service", service);
        } else {
            localStorage.removeItem("xa_service");
        }

        const enablePreferredTime = urlLoc.searchParams.get("enablePreferredTime");
        if (enablePreferredTime) {
            localStorage.setItem("xa_enablePreferredTime", enablePreferredTime.toLowerCase());
        } else {
            localStorage.removeItem("xa_enablePreferredTime");
        }

        const origin = urlLoc.searchParams.get("origin");
        if (origin) {
            localStorage.setItem("xa_origin", origin);
        } else {
            localStorage.removeItem("xa_origin");
        }

        // these are for tracking Google Actions from the Business Profile
        const rwgToken = urlLoc.searchParams.get("rwg_token");
        if (rwgToken) {
            // store on local storage
            localStorage.setItem("xa_rwg_token", rwgToken);
        } else {
            localStorage.removeItem("xa_rwg_token");
        }

        const merchantId = urlLoc.searchParams.get("merchant_id");
        if (merchantId) {
            // store on local storage
            localStorage.setItem("xa_merchant_id", merchantId);
        } else {
            localStorage.removeItem("xa_merchant_id");
        }

        const environment =
            urlLoc.searchParams.get("environment") || urlLoc.searchParams.get("env");
        if (environment) {
            localStorage.setItem("xa_environment", environment);
        } else {
            localStorage.removeItem("xa_environment");
        }

        // Extract and store tracking parameters (UTM parameters, click IDs, etc.)
        const trackingParameters = getAllTrackingParameters(window.location.href, {
            persistToLocalStorage: true,
            persistenceDays: 30,
            preferUrlParameters: true,
        });

        // Log tracking parameters for debugging (development only)
        if (process.env.NODE_ENV === "development" && Object.keys(trackingParameters).length > 0) {
            console.log("[ContactApp] Captured tracking parameters:", trackingParameters);
        }

        setDisablePoweredBy(disablePoweredBy);
        setPoweredByMessage(poweredByMessage);
        setPoweredByUrl(poweredByUrl);

        if (!key || key.trim().length === 0) {
            setError(Error(`Missing widget key id`));
            return;
        }

        const urlConfig = `https://form.xapp.ai/config.json?key=${key}${
            rwgToken ? `&rwg_token=${rwgToken}` : ""
        }`;

        let rawResponse: string;

        fetch(urlConfig)
            .then(async (resp) => {
                rawResponse = await resp.text();
                return JSON.parse(rawResponse);
            })
            .then((json) => {
                const overrides: Partial<FormWidgetEnv> = {
                    // add over-writable values here
                    businessName,
                    businessAddress,
                    businessLogoUrl,
                    businessWebsite,
                    chatWidgetKey,
                    partnerId,
                };

                // clean off undefined values off overrides so they don't clean off values coming in from the config
                Object.keys(overrides).forEach((key: string) => {
                    if (!overrides[key as keyof FormWidgetEnv]) {
                        delete overrides[key as keyof FormWidgetEnv];
                    }
                });

                // clear off undefined values from overrides
                // Ensure the URL key is passed through for event tracking
                const connection = buildConnection(key, json.connection);

                const updated: FormWidgetEnv = {
                    ...json,
                    ...overrides,
                    connection,
                } as FormWidgetEnv;

                const [config, theme] = parseWidgetEnv(updated);

                setEnv(updated);
                setConfig(config);
                setTheme(theme);

                // Initialize the Meta Pixel (fires a PageView) if configured for this customer.
                // Safe under StrictMode's double-invoked effects — initMetaPixel dedupes via its
                // internal initializedPixels Set.
                initMetaPixel(updated.metaPixelId);

                // Fetch partner details asynchronously
                if (partnerId) {
                    getPartnerDetailsAsync(partnerId)
                        .then((details) => {
                            setPartnerDetails(details);
                        })
                        .catch((error) => {
                            console.error("Failed to load partner details:", error);
                            // Continue without partner details on error
                        })
                        .finally(() => {
                            setLoading(false);
                        });
                } else {
                    setLoading(false);
                }
            })
            .catch((error) => {
                let errorMessage = error.message;
                if (rawResponse) {
                    errorMessage = `${errorMessage} - config.json => "${rawResponse}"`;
                }
                setError(new Error(errorMessage));
                setLoading(false);
            });
    }, []);

    if (error) {
        return (
            <div className="App">
                <div className="Error-Container">
                    <h3>I'm sorry, we had an error loading your web page.</h3>
                    <code>{error.message}</code>
                    <p>
                        Please email{" "}
                        <a
                            href={`mailto:support@xapp.ai?subject=Contact%20Page%20Error&body=Error%20Message:%20${encodeURIComponent(
                                error.message
                            )}%0AURL:%20${encodeURIComponent(window.location.href)}`}
                        >
                            support@xapp.ai
                        </a>{" "}
                        with this error message and the current URL.
                    </p>
                </div>
            </div>
        );
    }

    if (loading) {
        return (
            <div className="App">
                <div className="Loading">
                    <LoadingSpinner loadingText="Loading latest..." />
                </div>
            </div>
        );
    }

    if (!config) {
        return (
            <div className="App">
                <div className="Error-Container">
                    <h3>I'm sorry, we had an error loading the configuration for this page.</h3>
                    <p>
                        Please email{" "}
                        <a
                            href={`mailto:support@xapp.ai?subject=Contact%20Page%20Error&body=Error%20Message:%20${encodeURIComponent(
                                `Unable to load config`
                            )}%0AURL:%20${encodeURIComponent(window.location.href)}`}
                        >
                            support@xapp.ai
                        </a>{" "}
                        with this error message and the current URL.
                    </p>
                </div>
            </div>
        );
    }

    const businessName = env?.businessName;
    const businessAddress = env?.businessAddress;
    const businessLogoUrl = env?.businessLogoUrl;
    const businessWebsite = env?.businessWebsite;
    const chatWidgetKey = env?.chatWidgetKey;
    const partnerId = env?.partnerId;

    const backgroundColor =
        partnerDetails?.style?.backgroundColor ||
        theme?.standAlone?.backgroundColor ||
        theme?.headerBackgroundColor ||
        "#ffffff";

    const headerBackgroundColor =
        theme?.standAlone?.header?.backgroundColor || backgroundColor || "#ffffff";
    // we need to insure proper contrast for the business name
    let headerBusinessNameColor = theme?.standAlone?.header?.color;

    if (!headerBusinessNameColor || headerBusinessNameColor === headerBackgroundColor) {
        // if it doesn't exist or is the exact same as the background color, we need to invert it
        headerBusinessNameColor = invertColor(headerBackgroundColor, true);
    }

    return (
        <>
            <HelmetProvider>
                <Helmet>
                    <title>{businessName || "Contact Us"}</title>
                    <meta
                        name="description"
                        content={
                            businessName ? `Get in touch with ${businessName}` : "Get in touch"
                        }
                    />
                    {chatWidgetKey && (
                        <script
                            id={"xapp-js"}
                            src={`https://widget.xapp.ai/xapp-chat-widget.js?key=${chatWidgetKey}`}
                        ></script>
                    )}
                </Helmet>
            </HelmetProvider>

            <WidgetStylesheet theme={theme} />

            <ContactPage
                config={config}
                businessName={businessName}
                businessAddress={businessAddress}
                businessLogoUrl={businessLogoUrl}
                businessWebsite={businessWebsite}
                partnerId={partnerId}
                partnerDetails={partnerDetails}
                theme={{
                    backgroundColor,
                    headerBackgroundColor,
                    headerBusinessNameColor,
                }}
                disablePoweredBy={disablePoweredBy}
                poweredByMessage={poweredByMessage}
                poweredByUrl={poweredByUrl}
                onSubmit={handleSubmit}
            />
        </>
    );
}

export default App;
