let Tween = createjs.Tween;
createjs.Ticker.timingMode = createjs.Ticker.RAF;

let partCounts = {
    "hair":9,
    "skin":3,
    "eyes":3,
    "top":6,
    "tie":3
};
let topColors = [
    "#AC8A58",
    "#0E0F2A",
    "#252525",
    "#000000",
    "#EDC1C1",
    "#C1E6ED"
];

let imageNames = [
    "shadow",
    "ring",
    "whitering"
];

let imageAssets = {};
for (let i = 0; i < imageNames.length; i++) {
    let img = new Image();
    img.src = "/static/"+imageNames[i]+".png";
    imageAssets[imageNames[i]] = img;
}
for (let part in partCounts) {
    if (partCounts.hasOwnProperty(part)) {
        imageAssets[part] = [];
        for (let i = 0; i < partCounts[part]; i++) {
            let img = new Image();
            img.src = "/static/parts/"+part+i.toString()+".png";
            imageAssets[part].push(img);
        }
    }
}

let soundAssets = {
    "transmit":(new Audio("/static/transmit.wav")),
    "boom":(new Audio("/static/boom.wav")),
    "good":(new Audio("/static/good.wav")),
    "bad":(new Audio("/static/bad.wav"))
};

let suspects = [];
let role = null;
let characterLimit = 0;
let status = "waiting";
let message = "";
let assassinDisplayOrder = [];
let wasShot = 0;

let canvas = document.getElementById("gameCanvas");
let ctx = canvas.getContext("2d");
let messageInput = document.getElementById('messageInput');
let sight = document.getElementById('sight');

let sightCurrentPos = [window.innerWidth/2,window.innerHeight/2];
let sightGoalPos = [window.innerWidth/2,window.innerHeight/2];

let globalAnim = {
    "showLetters":0
};

let goreParticles = [];

function renderSuspect(suspect,x,y) { //position is center bottom
    ctx.drawImage(imageAssets["shadow"],x-53,y-5);
    ctx.fillStyle = topColors[suspect["top"]];
    ctx.fillRect(x-45,y-suspect["height"],89,suspect["height"]);
    ctx.fillStyle = "#FFFFFF";
    ctx.fillRect(x-45,y-suspect["height"]-97,89,97);
    if ("tie" in suspect)
        ctx.drawImage(imageAssets["tie"][suspect["tie"]],x-8,y-suspect["height"]-97);
    ctx.drawImage(imageAssets["top"][suspect["top"]],x-45,y-suspect["height"]-97);
    ctx.drawImage(imageAssets["skin"][suspect["skin"]],x-45,y-suspect["height"]-97-79);
    ctx.drawImage(imageAssets["eyes"][suspect["eyes"]],x-24,y-suspect["height"]-97-62);
    if (suspect["hair"] % 3 === 0)
        ctx.drawImage(imageAssets["hair"][suspect["hair"]],x-45,y-suspect["height"]-97-79);
    else
        ctx.drawImage(imageAssets["hair"][suspect["hair"]],x-45,y-suspect["height"]-97-79-imageAssets["hair"][suspect["hair"]].height);
}

function spawnSuspectGore(suspect,x,y) {
    for (let layer = 0; layer < 2; layer++) {
        for (let r = 0; r < 22; r++) {
            for (let c = 0; c < 9; c++) {
                let particle = {
                    "x": x - 45 + (10 * c),
                    "y": y - 10 - (r * 10) - 3,
                    "vx": (c - 4.5) * 2 + (Math.random() * 3 - 1.5),
                    "vy": -(r - 11) + (Math.random() * 3 - 1.5),
                    "opacity": 1
                };
                let mag = Math.sqrt(particle["vx"] * particle["vx"] + particle["vy"] * particle["vy"]);
                let goalMag = 3+Math.random()*10;
                particle["vx"] = particle["vx"] * goalMag/mag;
                particle["vy"] = particle["vy"] * goalMag/mag;
                if (layer === 0)
                    particle["color"] = "#FF0000";
                else if (r < 15)
                    particle["color"] = topColors[suspect["top"]];
                else
                    particle["color"] = "#A6754D";
                goreParticles.push(particle);
            }
        }
    }
}

function draw() {
    ctx.clearRect(0,0,854,480);
    //particles
    for (let i = 0; i < goreParticles.length; i++) {
        let particle = goreParticles[i];
        if (particle["y"] > 500) {
            goreParticles.splice(i, 1);
            i--;
            continue;
        }
        ctx.fillStyle = particle["color"];
        ctx.globalAlpha  = particle["opacity"];
        ctx.fillRect(particle["x"],particle["y"],10,10);
        particle["vy"] += 0.8;
        particle["y"] += particle["vy"];
        particle["x"] += particle["vx"];
        if (particle["opacity"] > 0)
            particle["opacity"] -= 0.03;
        if (particle["opacity"] < 0)
            particle["opacity"] = 0;
    }
    ctx.globalAlpha = 1;
    //suspects
    let assassinHover = false;
    for (let i = 0; i < suspects.length; i++) {
        if (role === "controller" && i === 0) {
            ctx.drawImage(imageAssets["ring"], suspects[i]["pos"] - 87.5, 380 - 20);
            ctx.textAlign = "center";
            ctx.fillStyle = "#FF0909";
            ctx.shadowColor = "rgba(0,0,0,0.25)";
            ctx.shadowBlur = 7;
            ctx.font = "20px 'Do Hyeon'";
            ctx.fillText("TARGET",suspects[i]["pos"],110);
            ctx.shadowBlur=0; //turn this off again
        }
        if (role === "assassin" && status === "picking") {
            if (lastMousePos[0]-(window.innerWidth/2)+427 > suspects[i]["pos"] - 55 && lastMousePos[0]-(window.innerWidth/2)+427 < suspects[i]["pos"] + 55
            && lastMousePos[1] > (window.innerHeight/2)-240 && lastMousePos[1] < (window.innerHeight/2)+240) {
                ctx.drawImage(imageAssets["whitering"],suspects[i]["pos"]-87.5,380-20);
                assassinHover = true;
            }
        }
        if (!(
            (status === "won" || status === "roundOver" || status === "lost")
            && (i === wasShot)
        ))
        renderSuspect(suspects[i], suspects[i]["pos"], 380);
    }
    ctx.fillStyle = "#FFFFFF";
    if (role === "assassin" && status === "picking") {
        if (assassinHover) {
            sight.classList.add('grow');
        }
        else {
            sight.classList.remove('grow');
        }
    }
    if (status === "writing") {
        if (role === "assassin") {
            ctx.textAlign="center";
            ctx.font="40px 'Do Hyeon'";
            ctx.fillText("Waiting for transmission...",427,50);
        }
        if (role === "controller") {
            ctx.textAlign="center";
            ctx.font="40px 'Do Hyeon'";
            ctx.fillText("Describe the Target",427,50);
            ctx.font="20px 'Do Hyeon'";
            ctx.fillText((characterLimit-messageInput.value.length).toString()+" characters remaining",427,450);
        }
    }
    if (status === "picking") {
        if (role === "assassin") {
            ctx.textAlign="center";
            ctx.font="25px 'Do Hyeon'";
            ctx.fillText("Incoming Transmission:",427,40);
            ctx.font="30px monospace";
            let messageWidth = ctx.measureText(message.substring(0,Math.ceil(globalAnim["showLetters"]))).width;
            ctx.fillStyle = "#000000";
            ctx.fillRect(427-(messageWidth/2)-5,55,messageWidth+10,35);
            ctx.fillStyle = "#FFFFFF";
            ctx.fillText(message.substring(0,Math.ceil(globalAnim["showLetters"])),427,80);
            ctx.font="20px 'Do Hyeon'";
            ctx.fillText("Who to shoot?",427,440);
        }
        if (role === "controller") {
            ctx.textAlign="center";
            ctx.font="40px 'Do Hyeon'";
            ctx.fillText("Assassin is Picking...",427,50);
            sightCurrentPos = [
                sightCurrentPos[0]+(sightGoalPos[0]-sightCurrentPos[0])*0.15,
                sightCurrentPos[1]+(sightGoalPos[1]-sightCurrentPos[1])*0.15
            ];
            sight.style.left = sightCurrentPos[0]+"px";
            sight.style.top = sightCurrentPos[1]+"px";
        }
    }
    window.requestAnimationFrame(draw);
}
draw();

let ws = new WebSocket("ws://" + window.location.hostname + "/websocket");
ws.onopen = function (event) {
    let msgObj = {
        "action":"joinGame",
        "gameId":gameId
    };
    ws.send(JSON.stringify(msgObj));
};
ws.onmessage = function (event) {
    let incomingObj = JSON.parse(event.data);
    if (incomingObj["action"] !== "sight")
        console.log(incomingObj);
    if ("error" in incomingObj) {
        alert("Error: "+incomingObj["error"]);
    }
    if (incomingObj["action"] === "joined") {
        role = incomingObj["role"];
        if (role === "assassin") {
            document.getElementById("assassinIntroBox").style.display = "block";
            document.getElementById("urlInstruction").style.display = "block";
            document.querySelector("#assassinIntroBox .startButton").addEventListener("click", function() {
                ws.send(JSON.stringify({"action":"ready"}));
                document.querySelector("#assassinIntroBox .startButton").style.display = "none";
                document.querySelector("#assassinIntroBox .waitingMessage").style.display = "block";
            });
        }
        else if (role === "controller") {
            document.getElementById("controllerIntroBox").style.display = "block";
            document.querySelector("#controllerIntroBox .startButton").addEventListener("click", function() {
                ws.send(JSON.stringify({"action":"ready"}));
                document.querySelector("#controllerIntroBox .startButton").style.display = "none";
                document.querySelector("#controllerIntroBox .waitingMessage").style.display = "block";
            });
        }
    }
    if (incomingObj["action"] === "suspects") {
        document.getElementById("assassinIntroBox").style.display = "none";
        document.getElementById("controllerIntroBox").style.display = "none";
        document.getElementById("urlInstruction").style.display = "none";
        document.getElementById("successBox").style.display = "none";
        suspects = incomingObj["suspects"];
        let colWidth = (854/(suspects.length+1));
        for (let i = 0; i < suspects.length; i++) {
            suspects[i]["pos"] = Math.round(colWidth+colWidth*i)-854;
            Tween.get(suspects[i])
            .wait((suspects.length*150)-(i*150))
            .to({
                "pos":Math.round(colWidth+colWidth*i)
            },400,createjs.Ease.sineOut);
        }
        status = "writing";
        if (role === "controller") {
            messageInput.value = "";
            messageInput.disabled = false;
            characterLimit = incomingObj["limit"];
            messageInput.size = characterLimit;
            messageInput.maxLength = characterLimit;
            messageInput.style.display = "block";
            messageInput.focus();
        }
    }
    if (incomingObj["action"] === "message") {
        status = "picking";
        sight.style.display = "block";
        message = incomingObj["message"];
        if (role === "assassin") {
            document.body.style.cursor = "none";
            globalAnim["showLetters"] = 0;
            Tween.get(globalAnim)
            .to({"showLetters":message.length},1500)
        }
        if (role === "controller") {
            messageInput.disabled = true;
            let colWidth = (854/(suspects.length+1));
            assassinDisplayOrder = incomingObj["order"];
            for (let i = 0; i < incomingObj["order"].length; i++) {
                Tween.get(suspects[incomingObj["order"][i]])
                .to({
                    "pos":Math.round(colWidth+colWidth*i)
                },500,createjs.Ease.sineInOut);
            }
        }
        soundAssets["transmit"].play();
    }
    if (incomingObj["action"] === "sight") {
        if (role === "controller") {
            sightGoalPos = [
                (incomingObj["x"] + (window.innerWidth/2) - 29),
                (incomingObj["y"] + (window.innerHeight/2) - 29)
            ];
        }
    }
    if (incomingObj["action"] === "choice") {
        sight.style.display = "none";
        document.body.style.cursor = "auto";
        if (role === "assassin")
            wasShot = incomingObj["choice"];
        else if (role === "controller")
            wasShot = assassinDisplayOrder[incomingObj["choice"]];
        spawnSuspectGore(suspects[wasShot],suspects[wasShot]["pos"],380);
        if (incomingObj["correct"] === true) {
            if (incomingObj["finished"] === true) {
                status = "won";
                setTimeout(function() {
                    document.getElementById("completeBox").style.display = "block";
                    soundAssets["good"].play();
                }, 1300);
            }
            else {
                status = "roundOver";
                setTimeout(function() {
                    document.getElementById("successBox").style.display = "block";
                    if (role === "controller") {
                        document.getElementById("continueButton").style.display = "none";
                        document.querySelector("#successBox .waitingMessage").style.display = "block";
                    }
                    soundAssets["good"].play();
                }, 1300);
            }
        }
        else {
            status = "lost";
            setTimeout(function() {
                document.getElementById("failedBox").style.display = "block";
                soundAssets["bad"].play();
            }, 1300);
        }
        soundAssets["boom"].play();
    }
};

messageInput.addEventListener("keyup", function(event) {
    if (event.keyCode === 13) {
        if (status === "writing" && role === "controller" && messageInput.value !== "") {
            ws.send(JSON.stringify({
                "action":"message",
                "message":messageInput.value
            }));
        }
    }
});

document.getElementById("continueButton").addEventListener("click",function() {
    ws.send(JSON.stringify({
        "action":"continue",
    }));
});

document.getElementById("restartButton").addEventListener("click",function() {
    document.location = "/";
});

document.addEventListener("click",function(event) {
    if (role === "assassin" && status === "picking") {
        for (let i = 0; i < suspects.length; i++) {
            if (lastMousePos[0]-(window.innerWidth/2)+427 > suspects[i]["pos"] - 55 && lastMousePos[0]-(window.innerWidth/2)+427 < suspects[i]["pos"] + 55
            && lastMousePos[1] > (window.innerHeight/2)-240 && lastMousePos[1] < (window.innerHeight/2)+240) {
                ws.send(JSON.stringify({
                "action":"choice",
                "choice":i
            }));
            }
        }
    }
});

let lastMousePos = [0,0];
let currentMousePos = [0,0];
function checkMouse() {
    if (role === "assassin") {
        if (status === "picking" && (lastMousePos[0] !== currentMousePos[0] || lastMousePos[1] !== currentMousePos[1])) {
            ws.send(JSON.stringify({
                "action":"sight",
                "x":currentMousePos[0]-(window.innerWidth/2),
                "y":currentMousePos[1]-(window.innerHeight/2)
            }));
            lastMousePos = currentMousePos;
        }
    }
}
setInterval(checkMouse,80);

window.addEventListener("mousemove",function(event) {
    if (role === "assassin") {
        sight.style.left = (event.clientX - 29) + "px";
        sight.style.top = (event.clientY - 29) + "px";
        currentMousePos = [event.clientX, event.clientY];
    }
});