import i18next from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import HttpApi from "i18next-http-backend";
import '@fortawesome/fontawesome-free/js/fontawesome';
import '@fortawesome/fontawesome-free/js/solid';
import '@fortawesome/fontawesome-free/js/regular';
import '@fortawesome/fontawesome-free/js/brands';
import './feedback.js';
import './main.scss';
import {send} from './telemetry';
import './sus.js';

/////////////////
// TRANSLATION //
/////////////////

async function initI18next() {
    await i18next
        .use(HttpApi)
        .use(LanguageDetector)
        .init({
            supportedLngs: ["en", "de"],
            nonExplicitSupportedLngs: true,
            fallbackLng: "de",
            debug: true,
            backend: {
                loadPath: "/i18n/{{lng}}.json",
            },
        });
}

function translatePageElements() {
    // Translate content inside a tag
    const translatableElements = document.querySelectorAll(
        "[data-i18n]",
    );
    translatableElements.forEach((el) => {
        const key = el.getAttribute("data-i18n");
        el.innerHTML = i18next.t(key);
    });
    // Translate alt texts
    const translatableAltTexts = document.querySelectorAll(
        "[alt-i18n-key]",
    );
    translatableAltTexts.forEach((el) => {
        const translation_key = el.getAttribute("alt-i18n-key");
        el.setAttribute("alt", i18next.t(translation_key));
    });

}

function bindLocaleSwitcher(initialValue) {
    const switcher = document.querySelector(
        "[data-i18n-switcher]",
    );
    switcher.value = initialValue;
    switcher.onchange = (e) => {
        i18next
            .changeLanguage(e.target.value)
            .then(translatePageElements)
            .then(updateCageCheck);
    };
}

(async function () {
    await initI18next();
    translatePageElements();
    bindLocaleSwitcher(i18next.resolvedLanguage);
    updateCageCheck();
})();

//////////
// TABS //
//////////


function initTabs(tabs, tabContent, activationClass) {
    tabs.forEach((tab) => {
        tab.addEventListener('click', (e) => {
            let selectedTabID = tab.getAttribute('data-tab-id');
            updateActiveTab(tabs, tab);
            updateActiveContent(tabContent, selectedTabID);
        })
    })
}

function updateActiveTab(tabs, selectedTabID) {
    tabs.forEach((tab) => {
        if (tab && tab.classList.contains(ACTIVATION_CLASS)) {
            tab.classList.remove(ACTIVATION_CLASS);
        }
    });
    selectedTabID.classList.add(ACTIVATION_CLASS);
}

function updateActiveContent(tabsContent, selectedTabID) {
    tabsContent.forEach((item) => {
        if (item && item.classList.contains(ACTIVATION_CLASS)) {
            item.classList.remove(ACTIVATION_CLASS);
        }
        let data = item.getAttribute('data-content-id');
        if (data === selectedTabID) {
            item.classList.add(ACTIVATION_CLASS);
        }
    });
}

const primaryTabs = [...document.querySelectorAll('#primary-tabs li')];
const primaryTabsContent = [...document.querySelectorAll('#tab-content div')];
const ACTIVATION_CLASS = 'is-active';

initTabs(primaryTabs, primaryTabsContent, ACTIVATION_CLASS);


////////////////
// CALCULATOR //
////////////////

const MINIMUM_BASE_AREA = 0.5;
const MINIMUM_AREA_THREE_RATS = 1.5;
const AREA_PER_ADDITIONAL_RAT = 0.25;
const MAXIMUM_FALL_HEIGHT = 0.5;
const MINIMUM_LENGTH_LONG_SIDE = 0.8;
const MINIMUM_LENGTH_SHORT_SIDE = 0.5;
const MINIMUM_FLOOR_HEIGHT = 0.25;

const FAILED_BASE_AREA = "failed_base_area";
const FAILED_OVERALL_AREA = "failed_overall_area";
const FAILED_FALL_HEIGHT = "failed_fall_height";
const FAILED_NUM_RATS = "failed_num_rats";
const FAILED_MINIMUM_LENGTH_LONG_SIDE = "failed_length_long_side";
const FAILED_MINIMUM_LENGTH_SHORT_SIDE = "failed_length_short_side";
const FAILED_FLOOR_HEIGHT = "failed_floor_height"


const CRITERIA_BASE_AREA = "base_area";
const CRITERIA_FALL_HEIGHT = "fall_height";
const CRITERIA_MINIMUM_LENGTH_LONG_SIDE = "length_long_side";
const CRITERIA_MINIMUM_LENGTH_SHORT_SIDE = "length_short_side";
const CRITERIA_FLOOR_HEIGHT = "floor_height"
const CRITERIA_OVERALL_AREA = "overall_area"


class Validator {
    constructor() {
        this.FAIL_CRITERIA = {
            [FAILED_BASE_AREA]: i18next.t('failed-base-area', {"MINIMUM_BASE_AREA": MINIMUM_BASE_AREA}),
            [FAILED_OVERALL_AREA]: i18next.t("failed-overall-area"),
            [FAILED_FALL_HEIGHT]: i18next.t("failed-fall-height", {"maximum_fall_height": (MAXIMUM_FALL_HEIGHT * 100).toFixed(0)}),
            [FAILED_FLOOR_HEIGHT]: i18next.t("failed-floor-height", {"minimum_floor_height": (MINIMUM_FLOOR_HEIGHT * 100).toFixed(0)}),
            [FAILED_NUM_RATS]: i18next.t("failed-num-rats"),
            [FAILED_MINIMUM_LENGTH_LONG_SIDE]: i18next.t("failed-minimum-length-long-side", {"minimum_length_long_side": (MINIMUM_LENGTH_LONG_SIDE * 100).toFixed(0)}),
            [FAILED_MINIMUM_LENGTH_SHORT_SIDE]: i18next.t("failed-minimum-length-short-side", {"minimum_length_short_side": (MINIMUM_LENGTH_SHORT_SIDE * 100).toFixed(0)}),
        };
        this.STATIC_CRITERIA = {
            [CRITERIA_BASE_AREA]: i18next.t('base-area', {"MINIMUM_BASE_AREA": MINIMUM_BASE_AREA}),
            [CRITERIA_FALL_HEIGHT]: i18next.t("fall-height", {"maximum_fall_height": (MAXIMUM_FALL_HEIGHT * 100).toFixed(0)}),
            [CRITERIA_FLOOR_HEIGHT]: i18next.t("floor-height", {"minimum_floor_height": (MINIMUM_FLOOR_HEIGHT * 100).toFixed(0)}),
            [CRITERIA_MINIMUM_LENGTH_LONG_SIDE]: i18next.t("minimum-length-long-side", {"minimum_length_long_side": (MINIMUM_LENGTH_LONG_SIDE * 100).toFixed(0)}),
            [CRITERIA_MINIMUM_LENGTH_SHORT_SIDE]: i18next.t("minimum-length-short-side", {"minimum_length_short_side": (MINIMUM_LENGTH_SHORT_SIDE * 100).toFixed(0)}),
        }
    }

    overallAreaNeeded(numOfRats) {
        if (numOfRats < 3 || numOfRats > 15) {
            throw new Error("This formula works only from 3 to 15 rats");
        }
        return MINIMUM_AREA_THREE_RATS + (numOfRats - 3.0) * AREA_PER_ADDITIONAL_RAT;
    }

    allowedNumberOfRats(overallArea) {
        /*
        Calculates the number of rats that are allowed for a certain overall area.
         */
        let result = 3.0 + (overallArea - MINIMUM_AREA_THREE_RATS) / AREA_PER_ADDITIONAL_RAT;
        if (result < 3) {
            throw new Error("Cages must be for three rats or more");
        }
        return result;
    }

    failCageNumberIndependent(dimensions, numFullFloors) {
        /*
        Function that checks a cage independent of the number of rats.
         */
        let failedCriteria = {};

        const baseArea = dimensions.depth * dimensions.width;
        if (baseArea < MINIMUM_BASE_AREA) {
            failedCriteria[FAILED_BASE_AREA] = this.FAIL_CRITERIA[FAILED_BASE_AREA];
        }

        if (dimensions.height / numFullFloors > MAXIMUM_FALL_HEIGHT) {
            failedCriteria[FAILED_FALL_HEIGHT] = this.FAIL_CRITERIA[FAILED_FALL_HEIGHT];
        }

        if (dimensions.width < MINIMUM_LENGTH_LONG_SIDE && dimensions.depth < MINIMUM_LENGTH_LONG_SIDE) {
            failedCriteria[FAILED_MINIMUM_LENGTH_LONG_SIDE] = this.FAIL_CRITERIA[FAILED_MINIMUM_LENGTH_LONG_SIDE];
        }

        if (dimensions.width < MINIMUM_LENGTH_SHORT_SIDE || dimensions.depth < MINIMUM_LENGTH_SHORT_SIDE) {
            failedCriteria[FAILED_MINIMUM_LENGTH_SHORT_SIDE] = this.FAIL_CRITERIA[FAILED_MINIMUM_LENGTH_SHORT_SIDE];
        }

        if (dimensions.height / numFullFloors < MINIMUM_FLOOR_HEIGHT) {
            failedCriteria[FAILED_FLOOR_HEIGHT] = this.FAIL_CRITERIA[FAILED_FLOOR_HEIGHT];
        }

        return failedCriteria;
    }

    getOverallArea(dimensions, numFullFloors) {
        const baseArea = dimensions.depth * dimensions.width;
        return baseArea * numFullFloors
    }

    cageCheck(dimensions, numRats, numFullFloors) {
        /*
        Function that checks a cage based on overall criteria and the number of rats.
         */
        let failedCriteria = this.failCageNumberIndependent(dimensions, numFullFloors);

        if (numRats < 2 || numRats > 15) {
            failedCriteria[FAILED_NUM_RATS] = this.FAIL_CRITERIA[FAILED_NUM_RATS];
        }

        const overallArea = this.getOverallArea(dimensions, numFullFloors);
        const overallAreaNeeded = this.overallAreaNeeded(numRats);
        if (overallArea < overallAreaNeeded) {
            failedCriteria[FAILED_OVERALL_AREA] = this.FAIL_CRITERIA[FAILED_OVERALL_AREA];
        }

        return failedCriteria;
    }


}

class Dimensions {
    constructor(width, depth, height) {
        this.width = width;
        this.depth = depth;
        this.height = height;
    }

    toString() {
        return `${this.width}x${this.depth}x${this.height}`;
    }

    static fromDict(data) {
        const {width, depth, height} = data;
        return new Dimensions(width, depth, height);
    }
}


//////////////////////////
// DOCUMENT INTERACTION //
//////////////////////////

///////
// 1 //
///////

const numRatsCalculatorInputWidth = document.getElementById("num-rats-width");
numRatsCalculatorInputWidth.onchange = updateNumRatsCalculator;
const numRatsCalculatorInputDepth = document.getElementById("num-rats-depth");
numRatsCalculatorInputDepth.onchange = updateNumRatsCalculator;
const numRatsCalculatorInputHeight = document.getElementById("num-rats-height");
numRatsCalculatorInputHeight.onchange = updateNumRatsCalculator;

let numRatsNumFullFloors = document.getElementById("num-rats-numFullFloors");
numRatsNumFullFloors.oninput = function () {
    updateNumRatsCalculator();
}

///////
// 2 //
///////


let cageCalcLabelNumRats = document.getElementById("cageCalcLabelNumRats");

let cageCalcRatSlider = document.getElementById("cageCalcNumRats");

cageCalcRatSlider.oninput = function () {
    updateCageCalc();
}


///////
// 3 //
///////

const inputWidth = document.getElementById("width");
inputWidth.onchange = updateCageCheck;
const inputDepth = document.getElementById("depth");
inputDepth.onchange = updateCageCheck;
const inputHeight = document.getElementById("height");
inputHeight.onchange = updateCageCheck;

let fullFloorNum = document.getElementById("numFullFloors");
fullFloorNum.oninput = function () {
    updateCageCheck();
}


let labelNumRats = document.getElementById("labelNumRats");

let ratSlider = document.getElementById("numRats");

ratSlider.oninput = function () {
    updateCageCheck();
}


function getResultFromChecks(checks) {
    if (Object.keys(checks).length > 0) {
        const ul = document.createElement('ul');
        for (const key in checks) {
            const li = document.createElement('li');
            li.textContent = `❌ ` + checks[key];
            ul.appendChild(li);
        }
        return ul;
    } else {
        const p = document.createElement('p');
        p.innerHTML = "✅ " + i18next.t("cage-complies-with-all-criteria")
        return p;
    }

}


function formatCriteria(criteria) {
    const ul = document.createElement('ul');
    for (const key in criteria) {
        const li = document.createElement('li');
        li.textContent = `☑️ ` + criteria[key];
        ul.appendChild(li);
    }
    return ul;

}

function updateCageCheck() {
    labelNumRats.innerHTML = i18next.t("cage-for-x-rats", {"num_rats": ratSlider.value});

    const width = inputWidth.value
    const depth = inputDepth.value
    const height = inputHeight.value
    const dimensions = new Dimensions(width / 100, depth / 100, height / 100);
    const validator = new Validator();
    const numRats = ratSlider.value;
    const numFullFloors = fullFloorNum.value;


    const failed_checks = validator.cageCheck(dimensions, numRats,);
    let resultsDiv = document.getElementById("resultsDiv");

    const result = getResultFromChecks(failed_checks);

    resultsDiv.innerHTML = "";
    resultsDiv.appendChild(result);

    // Send telemetry
    send("Update.CageCheck", {
        width: width,
        depth: depth,
        height: height,
        numRats: numRats,
        numFullFloors: numFullFloors
    });
}

function updateCageCalc() {
    let numRats = cageCalcRatSlider.value
    cageCalcLabelNumRats.innerHTML = i18next.t("cage-for-x-rats", {"num_rats": numRats});
    const validator = new Validator();
    let criteria = validator.STATIC_CRITERIA;
    let minimumOverallArea = validator.overallAreaNeeded(numRats);
    criteria[CRITERIA_OVERALL_AREA] = i18next.t('overall-area', {
        "numRats": numRats,
        "minimumOverallArea": minimumOverallArea
    });

    let resultsDiv = document.getElementById("cageCalcResultsDiv");

    const result = formatCriteria(criteria);

    resultsDiv.innerHTML = "";
    resultsDiv.appendChild(result);

    // Send telemetry
    send("Update.CageCalc", {
        numRats: numRats,
    });


}

function updateNumRatsCalculator() {

    const width = numRatsCalculatorInputWidth.value;
    const depth = numRatsCalculatorInputDepth.value;
    const height = numRatsCalculatorInputHeight.value;
    const numFullFloors = numRatsNumFullFloors.value;
    const dimensions = new Dimensions(width / 100, depth / 100, height / 100);
    const validator = new Validator();
    const failed_checks = validator.failCageNumberIndependent(dimensions, numFullFloors);

    let overallArea = validator.getOverallArea(dimensions, );
    let allowedNumRats;
    try {
        allowedNumRats = validator.allowedNumberOfRats(overallArea);
    } catch (e) {
        console.log(e);
        failed_checks[FAILED_BASE_AREA] = validator.FAIL_CRITERIA[FAILED_OVERALL_AREA];
        allowedNumRats = 0;
    }


    let resultsDiv = document.getElementById("num-rats-resultsDiv");

    const result = getResultFromChecks(failed_checks);

    resultsDiv.innerHTML = "";
    const p = document.createElement('p');
    p.textContent = i18next.t("cage-for-x-rats", {"num_rats": allowedNumRats});
    resultsDiv.appendChild(p);
    resultsDiv.appendChild(result);



    // Send telemetry
    send("Update.NumRatsCalc", {
        width: width,
        depth: depth,
        height: height,
        numFullFloors: numFullFloors
    });
}
