import { cookieNames, cookieExpirations } from '@/constants/cookie-names';
import applicationConfig from '@/constants/application-config';
import { useMainStore } from '@/store';

/**
 * @function isLocalhost
 */
function isLocalhost() {
    // eslint-disable-next-line no-restricted-globals
    return location.hostname.includes('localhost');
}

/**
 * @function getCookieValueByName
 * @param {string} name
 * @summary
 * Gets cookie value by name, returns empty string if not found.
 */
function getCookieValueByName(name) {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);

    if (parts.length === 2) {
        return parts.pop().split(';').shift();
    }
    return '';
}

/*
    Gets current domain without the subdomain for cookie.
*/
function getDomainWithoutSubdomain() {
    // eslint-disable-next-line no-restricted-globals
    const url = location.hostname;
    if (isLocalhost()) {
        return 'localhost';
    }

    const urlParts = url.split('.');

    return `.${urlParts
        .slice(0)
        .slice(-(urlParts.length === 4 ? 3 : 2))
        .join('.')}`;
}

/*
    Gets cookie domain value. Localhost will be empty "".
*/
export function getCookieDomainValue() {
    return isLocalhost() ? '' : `domain=${getDomainWithoutSubdomain()};`;
}

/*
    Used to create a cookie.
    `useDefaultISSCookieAttributes` will set the path and domain to our defaults
*/
function createOrUpdateCookie(
    key,
    value = '',
    { useDefaultISSCookieAttributes = true, maxAge, isSecure = true }
) {
    let cookieToAdd = `${key}=${value}; `;

    if (useDefaultISSCookieAttributes) {
        cookieToAdd += `path=${applicationConfig.COOKIE_PATH}; ${getCookieDomainValue()} `;
    }
    if (isSecure && !isLocalhost()) {
        cookieToAdd += 'secure; ';
    }
    if (!Number.isNaN(maxAge)) {
        cookieToAdd += `max-age=${maxAge};`;
    }

    document.cookie = cookieToAdd;
}

/*
    Gets the current instance of the ISS cookie.
    Returns null if cookie isn't valid JSON.
*/
export function getISSCookie() {
    const cookieJson = document.cookie
        ?.split('; ')
        ?.find((row) => row.startsWith(`${cookieNames.ISS_SESSION_INFO}=`))
        ?.split('=')[1];

    try {
        return JSON.parse(cookieJson);
    } catch (error) {
        return null;
    }
}

/*
    Used to set properties on the ISS cookie.
    Takes an object with properties to set. Will overwrite existing properties.
*/
export function setISSCookieProperties(properties) {
    if (typeof properties === 'object') {
        const cookie = getISSCookie();

        if (cookie !== null) {
            Object.keys(properties).forEach((key) => {
                cookie[key] = properties[key];
            });
        }

        const cookieValueJson = JSON.stringify(cookie ?? {});
        createOrUpdateCookie(cookieNames.ISS_SESSION_INFO, cookieValueJson, {});
    }
}

/*
    Will update the cookie if present, or create a new one if not.
*/
export function updateOrCreateISSCookie(forceCreate = false) {
    const store = useMainStore();

    // Set up cookie with all the props.
    if (forceCreate || store.order?.referralDate) {
        setISSCookieProperties({
            LastTouched: new Date().toUTCString(),
            SavedSessionTimeoutDate: store.applicationUser.savedSessionTimeout,
            ShouldResetState: false,
            ReferralNumber: store.order.referralNumber,
            ReferralDate: store.order.referralDate,
            ReferralCorrelationId: store.order.referralCorrelationId,
            ReferralParentAccountNumber: store.order.parentAccountNumber,
            SavedSessionId: store.applicationUser.savedSessionId,
            VehicleMake: store.order.vehicle?.make,
            VehicleModel: store.order.vehicle?.model
        });
    }
}

/*
    Removes cookie from browser.
*/
export function deleteISSCookie() {
    createOrUpdateCookie(cookieNames.ISS_SESSION_INFO, undefined, { maxAge: 0 });
}

/*
    Gets value of dxdev cookie, and then extracts "did" value from it.
    Returns empty string if cookie not found or "did" string not present.
*/
export function getDeviceIdValue() {
    // Sometimes these cookie contains more than the device ID.
    const cookieValue = getCookieValueByName(cookieNames.DXDEV);
    const cookieValuesSplit = cookieValue.split('=');

    // If this is the only value, just use that.
    if (cookieValuesSplit.length === 2 && cookieValuesSplit[0] === 'did') {
        return cookieValuesSplit[1];
    }

    const cookieValueMatch = cookieValue.match('^did=[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}');
    if (cookieValueMatch) {
        return cookieValueMatch[0].split('=')[1];
    }

    return '00000000-0000-0000-0000-000000000000';
}

/*
    Gets value of skey cookie, returns 0 if not found.
*/
export function getSessionKeyValue() {
    const cookieValue = getCookieValueByName(cookieNames.SESSION_KEY);

    if (cookieValue) {
        return cookieValue;
    }

    return 0;
}

/*
    Gets value of skey cookie, returns 0 if not found.
*/
export function getSessionIdValue() {
    const cookieValue = getCookieValueByName(cookieNames.SESSION_ID);

    if (cookieValue) {
        return cookieValue;
    }

    return '00000000-0000-0000-0000-000000000000';
}

/*
    Updates session ID cookie with new expiration date
*/
export function updateSessionIdCookie() {
    createOrUpdateCookie(cookieNames.SESSION_ID, getSessionIdValue(), { maxAge: 60 * 30 });
}

export function setCookieProperties(
    properties,
    { useDefaultISSCookieAttributes = true, maxAge, isSecure }
) {
    if (typeof properties === 'object') {
        Object.keys(properties).forEach((key) => {
            createOrUpdateCookie(key, properties[key], {
                useDefaultISSCookieAttributes,
                maxAge,
                isSecure
            });
        });
    }
}

export function isCookieSet(name) {
    const val = getCookieValueByName(name);

    return !!val;
}

export function regenerateDeviceId() {
    if (!isCookieSet(cookieNames.DXDEV)) {
        setCookieProperties(
            {
                [cookieNames.DXDEV]: `did=${crypto.randomUUID()}`
            },
            { maxAge: cookieExpirations.DXDEV }
        );
    }
}

export function regenerateUserId() {
    if (!isCookieSet(cookieNames.ISS_USER_ID)) {
        setCookieProperties(
            {
                [cookieNames.ISS_USER_ID]: crypto.randomUUID()
            },
            { maxAge: cookieExpirations.ISS_USER_ID }
        );
    }
}

export function getUserIdValue() {
    const cookieValue = getCookieValueByName(cookieNames.ISS_USER_ID);

    if (cookieValue) {
        return cookieValue;
    }

    return '00000000-0000-0000-0000-000000000000';
}

export function areAllSessionCookiesSet() {
    return (
        isCookieSet(cookieNames.SESSION_ID)
        && isCookieSet(cookieNames.DXDEV)
        && isCookieSet(cookieNames.ISS_SESSION_KEY)
        && isCookieSet(cookieNames.ISS_USER_ID)
    );
}

export function refreshCookieExpiration(name, expirationTime) {
    if (isCookieSet(name)) {
        createOrUpdateCookie(name, getCookieValueByName(name), { maxAge: expirationTime });
    }
}

export function refreshSessionExpiration() {
    refreshCookieExpiration(cookieNames.SESSION_ID, cookieExpirations.SESSION_ID);
    refreshCookieExpiration(cookieNames.DXDEV, cookieExpirations.DXDEV);
    refreshCookieExpiration(cookieNames.ISS_USER_ID, cookieExpirations.ISS_USER_ID);
    refreshCookieExpiration(cookieNames.ISS_SESSION_KEY, cookieExpirations.ISS_SESSION_KEY);
}

export function setSessionIdIfUnset(value) {
    if (!isCookieSet(cookieNames.SESSION_ID)) {
        setCookieProperties(
            {
                [cookieNames.SESSION_ID]: value
            },
            { maxAge: cookieExpirations.SESSION_ID }
        );
    }
}

export function setSessionKeyIfUnset(value) {
    if (!isCookieSet(cookieNames.ISS_SESSION_KEY)) {
        setCookieProperties(
            {
                [cookieNames.ISS_SESSION_KEY]: value
            },
            { maxAge: cookieExpirations.ISS_SESSION_KEY }
        );
    }
}
