import * as wasm from "./wasm/nexrad_browser.js";
await wasm.default();
wasm.__nxrd_browser_init();

console.log("[JS] setup event listeners");

console.log("[JS] initializing the renderer");

const DEFAULT_PREFERENCES = {
    RR: 5,
    RREN: true,
    FCS: 20
};
let preferences = DEFAULT_PREFERENCES;

function get_font_size() { return `${preferences.FCS}px monospace`; }

const canvas = document.getElementById("canvas");

function setupCanvas(canvas) {
    // Get the device pixel ratio, falling back to 1.
    var dpr = window.devicePixelRatio || 1;
    // Get the size of the canvas in CSS pixels.
    var rect = canvas.getBoundingClientRect();
    // Give the canvas pixel dimensions of their CSS
    // size * the device pixel ratio.
    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;
    var ctx = canvas.getContext('2d');
    // Scale all drawing operations by the dpr, so you
    // don't have to worry about the difference.
    ctx.scale(dpr, dpr);
    return ctx;
}

function rescaleCanvas(canvas, ctx) {
    var dpr = window.devicePixelRatio || 1;
    // Get the size of the canvas in CSS pixels.
    var rect = canvas.getBoundingClientRect();
    // Give the canvas pixel dimensions of their CSS
    // size * the device pixel ratio.
    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;
    // Scale all drawing operations by the dpr, so you
    // don't have to worry about the difference.
    ctx.scale(dpr, dpr);
}

const ctx = setupCanvas(canvas);

const FIFTY_MILES = 0.0916;
let current_lat = 38.8977;
let current_long = -77.036560;

function calcRenderbox() {
    return [current_long - FIFTY_MILES, current_lat - FIFTY_MILES, current_long + FIFTY_MILES, current_lat + FIFTY_MILES];
}

function latlongXY(lat, long) {
    let bbox = calcRenderbox();
    let pixelWidth = canvas.width;
    let pixelHeight = canvas.height;
    let bboxWidth = bbox[2] - bbox[0];
    let bboxHeight = bbox[3] - bbox[1];
    let widthPct = ( long - bbox[0] ) / bboxWidth;
    let heightPct = ( lat - bbox[1] ) / bboxHeight;
    let x = Math.floor( pixelWidth * widthPct );
    let y = Math.floor( pixelHeight * ( 1 - heightPct ) );
    return { x, y };
}

let x0 = 0;
let y0 = 0;
let xfull = canvas.width;
let yfull = canvas.height;

function recalcBorderCoordinates() {
    let xy = latlongXY(current_lat, current_long);

    x0 = xy.x - canvas.width;
    y0 = xy.y - canvas.height;
    xfull = x0 + canvas.width;
    yfull = y0 + canvas.width;
}

const red = "#ef0000";
const green = "#4af626";
const white = "#dedede";

let blinkyColor = "#dedede";

setInterval(() => {
    if (blinkyColor === red) {
        blinkyColor = white;
    } else {
        blinkyColor = red;
    }
}, 350);

function zulu() {
    let date = new Date();
    return `${date.getUTCHours().toString().padStart(2, '0')}:${date.getUTCMinutes().toString().padStart(2, '0')}:${date.getUTCSeconds().toString().padStart(2, '0')}Z`;
}

let command_buf = "";
let buf_response_mode = false;

let radar_inoperative = true;
let site_string = "SITE INFORMATION UNAVAILABLE";
let icao = "INOP";

let selected_mode = "INOP";

let delay_string = "DELAY UNAVAILABLE";

let display_buf = [];

function recalcDisplayBuf() {
    display_buf = [];
    let line = 0;
    for (let i = 0; i < command_buf.length; i++) {
        let char = command_buf[i];
        if (char === "\n") { line += 1; continue; }
        if (display_buf.length < line+1) { display_buf[line] = ""; }
        display_buf[line] += char;
    }
}

function cmd_err(err) {
    buf_response_mode = true;
    command_buf = err;
    recalcDisplayBuf();
}

let ar2 = undefined;

async function load() {
    const file = document.getElementById("file").files[0];
    const reader = new FileReader();
    reader.addEventListener('load', (event) => {
        let data = event.target.result;
        let loaded = wasm.load_ar2(data);
        console.log(loaded);
        cmd_err("");

        ar2 = loaded;
    });
    reader.readAsArrayBuffer(file);
}

function exec(command) {
    console.log("exec1!");

    let tokens = command.split(" ");

    if (tokens[0] === "MODE" && tokens[1] === "SET") {
        let mode = tokens[2];
        let valid_modes = ["REF", "VEL", "SW", "ZDR", "PHI", "RHO", "CFP"];
        if (!valid_modes.includes(mode)) {
            cmd_err("INVALID MODE");
            return;
        } else if (radar_inoperative) {
            cmd_err("RADAR INOPERATIVE\nCANNOT SET MODE");
            return;
        } else {
            selected_mode = mode;
            return;
        }
    }

    if (tokens[0] === "CLF" && tokens[1] === "OV") {
        document.getElementById("file").click();
        return;
    }

    if (tokens[0] === "CLF" && tokens[1] === "RELOAD") {
        // TRIGGER RELOAD
        cmd_err("SYSTEM PROCESSING");
        load();
        return;
    }

    if (command === "TEST UNSET INOP") {
        radar_inoperative = false;
        icao = "TEST";
        site_string = "TEST VCP 000 TEST AIR MODE";
        selected_mode = "REF";
        return;
    }

    if (command === "TEST INVALID COMMAND") {
        cmd_err("TEST SUCCESSFUL");
        return;
    }

    cmd_err("UNRECOGNIZED COMMAND");
}

function shouldNewline() {
    if (command_buf.startsWith("MODE SET")) { return true; }

    return false;
}

let ar2_date = undefined;

function convertDate() {
    if (ar2 !== undefined) {
        let unix_timestamp_millis = 86400000 * ar2.volume_header_record.date + ar2.volume_header_record.time;
        ar2_date = new Date(unix_timestamp_millis);
    } else {
        return undefined;
    }
}

function reRender() {
    if (ar2 !== undefined) {
        radar_inoperative = false;
        icao = ar2.volume_header_record.icao;
        site_string = `${icao} VCP INFORMATION UNAVAILABLE`;
        selected_mode = "REF";
    } else {
        radar_inoperative = true;
        icao = "INOP";
        site_string = "SITE INFORMATION UNAVAILABLE";
        selected_mode = "INOP";
    }

    convertDate();
    if (ar2_date !== undefined) {
        const delay = Date.now() - ar2_date;
        const SEC = 1000, MIN = 60 * SEC, HRS = 60 * MIN;
        const humanDiff = `${Math.floor(delay/HRS)}:${Math.floor((delay%HRS)/MIN).toLocaleString('en-US', {minimumIntegerDigits: 2})}:${Math.floor((delay%MIN)/SEC).toLocaleString('en-US', {minimumIntegerDigits: 2})}`;
        delay_string = "SITE DELAY " + humanDiff;
    }

    //document.getElementById("input-detection").focus();
    rescaleCanvas(canvas, ctx);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.resetTransform();

    recalcBorderCoordinates();

    let xy = latlongXY(current_lat, current_long);

    ctx.translate(xy.x, xy.y);

    // background (black, always)
    ctx.fillStyle = "black";
    ctx.fillRect(x0, y0, xfull * 2, yfull * 2);

    ctx.font = get_font_size();
    ctx.fillStyle = green;
    ctx.fillText(`NEXRAD ${icao} ${zulu()}`, x0 + 50, y0 + 50);

    if (radar_inoperative) {
        ctx.fillStyle = blinkyColor;
        ctx.fillText("RADR INOP NO DATA LOADED", x0 + 50, y0 + 50 + preferences.FCS);
        ctx.fillStyle = green;
    }

    ctx.textAlign = "right";
    ctx.fillText("RADAR SITE", xfull - 75, y0 + 50);
    ctx.fillText(`${site_string}`, xfull - 75, y0 + 50 + preferences.FCS);
    ctx.fillText(`${delay_string}`, xfull - 75, y0 + 50 + preferences.FCS * 2);

    ctx.fillText("MODE", xfull - 75, y0 + canvas.height / 3);

    // this hurts me physically

    if (selected_mode === "REF") {
        ctx.fillStyle = white;
        ctx.fillText(">REF<            ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS);
        ctx.fillStyle = green;
    } else {
        ctx.fillText(" REF             ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS);
    }

    if (selected_mode === "VEL") {
        ctx.fillStyle = white;
        ctx.fillText("      >VEL<      ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS);
        ctx.fillStyle = green;
    } else {
        ctx.fillText("       VEL       ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS);
    }

    if (selected_mode === "SW") {
        ctx.fillStyle = white;
        ctx.fillText("            >SW <", xfull - 75, y0 + canvas.height / 3 + preferences.FCS);
        ctx.fillStyle = green;
    } else {
        ctx.fillText("             SW  ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS);
    }

    if (selected_mode === "ZDR") {
        ctx.fillStyle = white;
        ctx.fillText(">ZDR<            ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS*2);
        ctx.fillStyle = green;
    } else {
        ctx.fillText(" ZDR             ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS*2);
    }

    if (selected_mode === "PHI") {
        ctx.fillStyle = white;
        ctx.fillText("      >PHI<      ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS*2);
        ctx.fillStyle = green;
    } else {
        ctx.fillText("       PHI       ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS*2);
    }

    if (selected_mode === "RHO") {
        ctx.fillStyle = white;
        ctx.fillText("            >RHO<", xfull - 75, y0 + canvas.height / 3 + preferences.FCS*2);
        ctx.fillStyle = green;
    } else {
        ctx.fillText("             RHO ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS*2);
    }

    if (selected_mode === "CFP") {
        ctx.fillStyle = white;
        ctx.fillText(" >CFP<           ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS*3);
        ctx.fillStyle = green;
    } else {
        ctx.fillText(" CFP             ", xfull - 75, y0 + canvas.height / 3 + preferences.FCS*3);
    }

    if (radar_inoperative) {
        ctx.fillStyle = red;
        ctx.fillText("      >RADR INOP<", xfull - 75, y0 + canvas.height / 3 + preferences.FCS * 3);
        ctx.fillStyle = green;
    }


    ctx.textAlign = "left";

    for (let line = 0; line < display_buf.length; line++) {
        ctx.fillText(display_buf[line], x0 + 50, y0 + canvas.height / 2 + (preferences.FCS * line));
    }
}

setInterval(reRender, 10);

document.onkeyup = (e) => {
    if (e.key.toUpperCase() === "ESCAPE") {
        command_buf = "";
    } else if (e.key.toUpperCase() === "ENTER") {
        let command = command_buf.replace("\n", " ");
        command_buf = "";
        exec(command);
    } else if (e.key.toUpperCase() === "BACKSPACE") {
        command_buf = command_buf.slice(0, command_buf.length - 1);
    } else if (e.key.toUpperCase() === " " && shouldNewline()) {
        command_buf += "\n";
    } else {
        if (e.key.length !== 1) { return; }
        if (buf_response_mode) {
            buf_response_mode = false;
            command_buf = "";
        }
        command_buf += e.key.toUpperCase();
    }
    recalcDisplayBuf();
    reRender();
}