/* eslint-disable max-lines */
/**
 * This file handles the hero-live-section and live-quickaccess functionality.
 */
import { onPageLoadComplete } from '@nimius/event-utility';
import { getCookie, setCookie } from '../utils/cookie-utility.js';
import { weatherIconMap } from '../utils/weather-icon-map.js';
import { ToubizV1Parser } from '@nimius/toubiz-opening-times-calculation';

let skiAreaData = null;
let weatherData = null;
let openingTimesData = null;

const skiAreaLiftsWrapperSelector = '[data-live-lifts-wrapper]';
const skiAreaSnowDepthWrapperSelector = '[data-live-snow-depth-wrapper]';
const openingTimesArticleIdSelector = '[data-live-opening-times-article-wrapper]';

const currentLang = document.documentElement.lang || 'de';
const translations = {
    de: {
        isOpen: {
            true: 'Geöffnet',
            false: 'Geschlossen',
        },
    },
    en: {
        isOpen: {
            true: 'Open',
            false: 'Closed',
        },
    },
    fr: {
        isOpen: {
            true: 'Ouvert',
            false: 'Fermé',
        },
    },
    it: {
        isOpen: {
            true: 'Aperto',
            false: 'Chiuso',
        },
    },
    es: {
        isOpen: {
            true: 'Abierto',
            false: 'Cerrado',
        },
    },
};

const fetchChannelContext = async () => {
    // Fetch channelContext to get toursprung apikey
    try {
        let channelContext = null;
        const url = `https://mein.toubiz.de/api/v1/channel/currentContext`;
        const randomId = Math.random().toString(26).substr(2);
        const apiToken = document.querySelector('[data-api-v2-article-key]')
            ?.getAttribute('data-api-v2-article-key') || '';
        const correlationId = `website-plus-${randomId}`;
        const bearer = `Bearer ${apiToken}`;

        if (!apiToken) {
            console.error('No Toubiz Api V2 Article key configured');

            return;
        }

        const options = {
            method: 'GET',
            headers: {
                'X-Toubiz-Correlation-Id': correlationId,
                'X-Toubiz-Referrer': location.href,
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'Authorization': bearer,
            },
        };

        const response = await fetch(url, options);

        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }

        channelContext = await response.json();

        return channelContext;
    } catch (error) {
        console.error('Fetch error:', error);
    }
};

const getToursprungApiKey = async () => {
    if (getCookie('toursprungApiKey')) {
        return getCookie('toursprungApiKey');
    } else {
        const channelContext = await fetchChannelContext();

        /* eslint-disable no-underscore-dangle */
        setCookie('toursprungApiKey', channelContext?._attributes?.channel?.toursprung?.apiKey);

        return channelContext?._attributes?.channel?.toursprung?.apiKey;
        /* eslint-enable no-underscore-dangle */
    }
};

const weatherApiFetch = async (lat, lon) => {
    /**
     * Use the 'toubiz' api key for development.
     *
     * let apiToken = 'toubiz';
     */
    let apiToken = await (getToursprungApiKey() || 'toubiz');

    const hours = 4;
    const url =
        `https://weather.maptoolkit.net/forecast/icon?api_key=${apiToken}&lat=${lat}&lng=${lon}&forecast=${hours}`;

    const response = await fetch(url, {
        method: 'GET',
    });

    if (response.status !== 200) {
        weatherData = null;

        throw new Error('Failed to fetch weather data');
    }

    weatherData = await response.json();

    return weatherData;
};
const skiAreaFetch = async (toubizId) => {
    const apiToken = document.querySelector('[data-api-v2-article-key]')
        ?.getAttribute('data-api-v2-article-key') || '';

    if (!apiToken) {
        console.error('No Toubiz Api V2 Article key configured');

        return;
    }

    try {
        const url = `https://mein.toubiz.de/api/v2/public/skiArea/${toubizId}?language=de`;

        const randomId = Math.random().toString(26).substr(2);
        const correlationId = `website-plus-${randomId}`;
        const bearer = `Bearer ${apiToken}`;

        const options = {
            method: 'GET',
            headers: {
                'X-Toubiz-Correlation-Id': correlationId,
                'X-Toubiz-Referrer': location.href,
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'Authorization': bearer,
            },
        };

        const response = await fetch(url, options);

        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }

        skiAreaData = await response.json();

        return skiAreaData;
    } catch (error) {
        console.error('Fetch error:', error);
    }
};
const openingTimesFetch = async (toubizId) => {
    const apiToken = document.querySelector('[data-api-v1-article-key]')
        ?.getAttribute('data-api-v1-article-key') || '';

    if (!apiToken) {
        console.error('No Toubiz Api V1 Article key configured');
        return;
    }

    try {
        // const url = `https://preview.toubiz.dev/api/v1/article/${toubizId}/openingTimes?language=de`;
        const url = `https://mein.toubiz.de/api/v1/article/${toubizId}/openingTimes?language=de`;

        const randomId = Math.random().toString(26).substr(2);
        const correlationId = `website-plus-${randomId}`;
        const bearer = `Bearer ${apiToken}`;

        const options = {
            method: 'GET',
            headers: {
                'X-Toubiz-Correlation-Id': correlationId,
                'X-Toubiz-Referrer': location.href,
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'Authorization': bearer,
            },
        };

        const response = await fetch(url, options);

        if (!response.ok) {
            throw new Error(`HTTP error! Status: ${response.status}`);
        }

        openingTimesData = await response.json();

        return openingTimesData;
    } catch (error) {
        console.error('Fetch error:', error);
    }
};

// Update DOM functions
const setWeatherData = () => {
    if (!weatherData) {
        // Hide weather section if no data is available
        const weatherDataWrappers = document.querySelectorAll('[data-live-weather-wrapper]');

        weatherDataWrappers.forEach((weatherDataWrapper) => {
            weatherDataWrapper?.classList.add('hidden');
        });

        return;
    }

    const weatherDataFields = document.querySelectorAll('[data-live-weather-degrees]') || [];
    const weatherIconFields = document.querySelectorAll('[data-live-weather-icon]') || [];
    const todayData = weatherData?.[ 0 ];

    const weatherIcon = () => {
        const weatherCode = todayData?.weather_code?.toString() ?? 'na';

        if (!weatherIconMap.has(weatherCode)) {
            return weatherIconMap.get('na');
        }

        return weatherIconMap.get(weatherCode);
    };

    weatherDataFields.forEach((field) => {
        field.textContent = `${Math.round(todayData?.temperature)} °C`;
    });
    weatherIconFields.forEach((field) => {
        field.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `#${weatherIcon()}`);
    });
};
const setSkiAreaData = () => {
    if (!skiAreaData) {
        // Hide sections if no data is available
        const skiAreaLiftsWrapper = document.querySelector(skiAreaLiftsWrapperSelector);
        const skiAreaSnowDepthWrapper = document.querySelector(skiAreaSnowDepthWrapperSelector);

        [ skiAreaLiftsWrapper, skiAreaSnowDepthWrapper ].forEach((item) => {
            item?.classList.add('hidden');
        });

        return;
    }

    const statistics = skiAreaData.payload?.statistics || [];
    const snowReports = skiAreaData.payload?.snowReports || [];
    const snowTransportationOpen = statistics.filter(statistic => statistic.type === 'snowTransportationOpen');
    const snowDepthMin = snowReports[ 0 ].depthMin;
    const snowDepthTop = snowReports[ 0 ].depthMax;
    const snowDepthOutput = snowDepthMin === snowDepthTop
        ? `${snowDepthMin} cm`
        : `${snowDepthMin} - ${snowDepthTop} cm`;

    const snowDepthFields = document.querySelectorAll('[data-live-snow-depth]') || [];
    const snowTransportationOpenFields = document.querySelectorAll('[data-live-lifts-open]') || [];

    snowDepthFields.forEach((field) => {
        field.textContent = snowDepthOutput;
    });

    snowTransportationOpenFields.forEach((field) => {
        field.textContent = `${snowTransportationOpen[ 0 ].number}/${snowTransportationOpen[ 0 ].total}`;
    });
};
const setOpeningTimesData = () => {
    const contentObjects = document.querySelectorAll('[data-live-opening-times-article-opening-times]');
    const hideWrapper = () => {
        const wrappers = document.querySelectorAll(openingTimesArticleIdSelector);

        wrappers.forEach((wrapper) => {
            wrapper?.classList.add('hidden');
        });
    };

    if (!openingTimesData.payload) {
        hideWrapper();
        return;
    }
    const collection = new ToubizV1Parser().parse(openingTimesData.payload);
    const parsedOpeningTimes = !collection || collection.times.length === 0
        ? null
        : collection;

    if (!parsedOpeningTimes) {
        hideWrapper();
        return;
    }

    const resolvedOpeningTimes = parsedOpeningTimes?.timesAt(new Date());

    contentObjects.forEach((field) => {
        field.textContent = translations[ currentLang ]?.isOpen?.[ resolvedOpeningTimes?.isOpen ] || '';
    });
};

const initLiveQuickaccessVisibility = (heroLiveSection, liveQuickaccess) => {
    const inactiveClass = 'c-live-quickaccess--inactive';

    if (!liveQuickaccess) {
        return;
    }
    if (!heroLiveSection) {
        liveQuickaccess.classList.remove(inactiveClass);
        return;
    }

    const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (!entry.isIntersecting) {
                liveQuickaccess.classList.remove(inactiveClass);
            } else {
                liveQuickaccess.classList.add(inactiveClass);
            }
        });
    }, {
        root: null,
        threshold: 0.1,
    });

    observer.observe(heroLiveSection);
};

// eslint-disable-next-line max-statements
onPageLoadComplete(async () => {
    const heroLiveSection = document.querySelector('[data-hero-live-section]');
    const liveQuickaccess = document.querySelector('[data-live-quickaccess]');
    const liveSectionContent = document.querySelectorAll('[data-live-section-content]');
    const liveSectionLoader = document.querySelectorAll('[data-live-section-loader]');
    const skiAreaLiftsWrapper = document.querySelector(skiAreaLiftsWrapperSelector);
    const skiAreaSnowDepthWrapper = document.querySelector(skiAreaSnowDepthWrapperSelector);
    const openingTimesArticleWrapper = document.querySelector(openingTimesArticleIdSelector);

    if (!heroLiveSection && !liveQuickaccess) {
        return;
    }

    initLiveQuickaccessVisibility(heroLiveSection, liveQuickaccess);

    const promises = [];
    const skiAreaToubizId = document.querySelector('[data-live-ski-area-toubiz-id]');
    const liveWeatherLat = document.querySelector('[data-live-weather-lat]');
    const liveWeatherLon = document.querySelector('[data-live-weather-lon]');
    const openingTimesArticleId = document.querySelector('[data-live-opening-times-article-id]');

    if (liveWeatherLat && liveWeatherLon) {
        const lat = liveWeatherLat.getAttribute('data-live-weather-lat');
        const lon = liveWeatherLon.getAttribute('data-live-weather-lon');

        promises.push(weatherApiFetch(lat, lon));
    }

    if (skiAreaToubizId && skiAreaLiftsWrapper && skiAreaSnowDepthWrapper) {
        const id = skiAreaToubizId.getAttribute('data-live-ski-area-toubiz-id');
        promises.push(skiAreaFetch(id));
    }

    if (openingTimesArticleId && openingTimesArticleWrapper) {
        const id = openingTimesArticleId.getAttribute('data-live-opening-times-article-id');
        promises.push(openingTimesFetch(id));
    }

    // Fetch content
    await Promise.allSettled(promises);

    // Show all content containers and hide all loaders
    liveSectionContent.forEach(item => item.classList.remove('hidden'));
    liveSectionLoader.forEach(item => item.classList.add('hidden'));

    // Update DOM
    setWeatherData();
    setSkiAreaData();
    setOpeningTimesData();
});
