import { state } from './store.js';
import { temperatureFormat, nodesDisconnectedAge, BASE_PATH } from './config.js';
import moment from 'moment';

export const timeSpans = {
    '1d': {name: '1 Day', amount: 86400},
    '3d': {name: '3 Days', amount: 259200},
    '7d': {name: '1 Week', amount: 604800},
    '14d': {name: '2 Weeks', amount: 1209600},
    '30d': {name: '1 Month', amount: 2592000},
    '90d': {name: '90 Days', amount: 7776000},
};

export function getTimeSpans() {
    return timeSpans;
};

export function getTimeSpan(value) {
    return timeSpans[value];
};

// convert node id to a hex colour
export function getNodeColor(nodeId) {
    return "#" + (nodeId & 0x00FFFFFF).toString(16).padStart(6, '0');
};

export function getNodeTextColor(nodeId) {
    // extract rgb components
    const r = (nodeId & 0xFF0000) >> 16;
    const g = (nodeId & 0x00FF00) >> 8;
    const b = nodeId & 0x0000FF;

    // calculate brightness
    const brightness = ((r * 0.299) + (g * 0.587) + (b * 0.114)) / 255;

    // determine text color based on brightness
    return brightness > 0.5 ? "#000000" : "#FFFFFF";
};

export function getRegionFrequencyRange(regionName) {
    // determine lora frequency range based on region_name
    // https://github.com/meshtastic/firmware/blob/a4c22321fca6fc8da7bab157c3812055603512ba/src/mesh/RadioInterface.cpp#L21
    const regionNameToLoraFrequencyRange = {
        "US": "902-928 MHz",
        "EU_433": "433-434 MHz",
        "EU_868": "869.4-869.65 MHz",
        "CN": "470-510 MHz",
        "JP": "920.8-927.8 MHz",
        "ANZ": "915-928 MHz",
        "RU": "868.7-869.2 MHz",
        "KR": "920-923 MHz",
        "TW": "920-925 MHz",
        "IN": "865-867 MHz",
        "NZ_865": "864-868 MHz",
        "TH": "920-925 MHz",
        "UA_433": "433-434.7 MHz",
        "UA_868": "868-868.6 MHz",
        "MY_433": "433-435 MHz",
        "MY_919": "919-924 MHz",
        "SG_923": "917-925 MHz",
        "LORA_24": "2.4-2.4835 GHz",
        "UNSET": "902-928 MHz",
    }
    return regionNameToLoraFrequencyRange[regionName] ?? null;
};

export function getShareLinkForNode(nodeId) {
    return window.location.origin + `/?node_id=${nodeId}`;
};

export function copyShareLinkForNode(nodeId) {
    // make sure copy to clipboard is supported
    if (!navigator.clipboard || !navigator.clipboard.writeText) {
        alert("Clipboard not supported. Site must be served via https on iOS.");
        return;
    }
    // copy share link to clipboard
    const url = getShareLinkForNode(nodeId);
    navigator.clipboard.writeText(url);
    // tell user we copied it
    alert("Link copied to clipboard!");
};

export function getColorForSnr(snr) {
    if(snr >= 0) return "#16a34a"; // good
    if(snr < 0) return "#dc2626"; // bad
};

export function getPositionPrecisionInMeters(positionPrecision) {
    switch (positionPrecision){
        case 2: return 5976446;
        case 3: return 2988223;
        case 4: return 1494111;
        case 5: return 747055;
        case 6: return 373527;
        case 7: return 186763;
        case 8: return 93381;
        case 9: return 46690;
        case 10: return 23345;
        case 11: return 11672; // Android LOW_PRECISION
        case 12: return 5836;
        case 13: return 2918;
        case 14: return 1459;
        case 15: return 729;
        case 16: return 364; // Android MED_PRECISION
        case 17: return 182;
        case 18: return 91;
        case 19: return 45;
        case 20: return 22;
        case 21: return 11;
        case 22: return 5;
        case 23: return 2;
        case 24: return 1;
        case 32: return 0; // Android HIGH_PRECISION
    }
    return null;
};

export function getTerrainProfileImage(node1, node2) {
    // line colour between nodes
    const lineColour = "0000FF"; // blue

    // node 1 (left side of image)
    const node1MarkerColour = "0000FF"; // blue
    const node1Latitude = node1.latitude;
    const node1Longitude = node1.longitude;
    const node1ElevationMSL = ""; // node1.altitude ?? "";

    // node 2 (right side of image)
    const node2MarkerColour = "0000FF"; // blue
    const node2Latitude = node2.latitude;
    const node2Longitude = node2.longitude;
    const node2ElevationMSL = ""; // node2.altitude ?? "";

    // generate terrain profile image url
    return "https://heywhatsthat.com/bin/profile-0904.cgi?" + new URLSearchParams({
        src: "meshtastic.liamcottle.net",
        axes: 1, // include grid lines and a scale
        metric: 1, // show metric units
        curvature: 0, // don't include the curvature of the earth in the graphic
        width: 500,
        height: 200,
        pt0: `${node1Latitude},${node1Longitude},${lineColour},${node1ElevationMSL},${node1MarkerColour}`,
        pt1: `${node2Latitude},${node2Longitude},${lineColour},${node2ElevationMSL},${node2MarkerColour}`,
    }).toString();
};

export function formatPositionPrecision(positionPrecision) {
    // get position precision in meters
    const positionPrecisionInMeters = getPositionPrecisionInMeters(positionPrecision);
    if (positionPrecisionInMeters == null){
        return "?";
    }

    // format kilometers
    if (positionPrecisionInMeters > 1000){
        const positionPrecisionInKilometers = Math.ceil(positionPrecisionInMeters / 1000);
        return `±${positionPrecisionInKilometers}km`;
    }

    // format meters
    return `±${positionPrecisionInMeters}m`;
};

// escape strings for tooltips etc, to prevent html/script injection
// not used in vuejs, as that auto escapes
export function escapeString(string) {
    return string.replace(/</g, "&lt;").replace(/>/g, "&gt;");
};

export function isMobile() {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
};

// returns true if the element or one of its parents has the class classname
export function elementOrAnyAncestorHasClass(element, className) {
    // check if element contains class
    if (element.classList && element.classList.contains(className)) {
        return true;
    }

    // check if parent node has the class
    if (element.parentNode) {
        return elementOrAnyAncestorHasClass(element.parentNode, className);
    }

    // couldn't find the class
    return false;
};

export function formatUptimeSeconds(secondsToFormat) {
    secondsToFormat = Number(secondsToFormat);
    const days = Math.floor(secondsToFormat / (3600 * 24));
    const hours = Math.floor((secondsToFormat % (3600 * 24)) / 3600);
    const minutes = Math.floor((secondsToFormat % 3600) / 60);
    const seconds = Math.floor(secondsToFormat % 60);
    const daysPlural = days === 1 ? 'day' : 'days';
    return `${days} ${daysPlural} ${hours}h ${minutes}m ${seconds}s`;
};

export function celsiusToFahrenheit(celsius) {
    return (celsius * 9/5) + 32;
};


/** operates on state */

// find node by id
export function findNodeById(id) {
    const node = state.nodes.find((node) => node.node_id.toString() === id.toString());
    if (node) return node;
    return null;
};

// find node marker by id
export function findNodeMarkerById(id) {
    return state.nodeMarkers[id] ?? null;
};

/** operates on config */

export function formatTemperature(celsius) {
    switch (temperatureFormat.value) {
        case "celsius": {
            return `${Number(celsius).toFixed(0)}ºC`;
        }
        case "fahrenheit": {
            const fahrenheit = celsiusToFahrenheit(celsius);
            return `${fahrenheit.toFixed(0)}ºF`;
        }
    }
}

export function getTemperatureUnit() {
    switch (temperatureFormat.value) {
        case "celsius": return "ºC";
        case "fahrenheit": return "ºF";
    }
};

export function buildPath(endpoint) {
    return `${BASE_PATH}${endpoint}`
};

// determine if node was recently heard uplinking packets to mqtt
export function hasNodeUplinkedToMqttRecently(node) {
    const now = moment();
    const millisecondsSinceNodeLastUplinkedToMqtt = now.diff(moment(node.mqtt_connection_state_updated_at));
    return millisecondsSinceNodeLastUplinkedToMqtt < nodesDisconnectedAge.value * 1000;
}