/**
 * @overview Life of German Reallife - Tuning tuning.js
 * @author hydrant
 * @copyright (c) 2008 - 2018 Life of German
 */

import * as NativeUI from '../libs/NativeUI';
const Menu = NativeUI.Menu;
const UIMenuItem = NativeUI.UIMenuItem;
const BadgeStyle = NativeUI.BadgeStyle;
const Point = NativeUI.Point;
const Color = NativeUI.Color;
let screenRes = mp.game.graphics.getScreenResolution(0, 0);
import vehicleColors from './colors';
import moneyformat from '../moneyformat';

export default function tuning(globalData: IGlobalData) {
    var keyBound = false;

    var currentPrimaryColor: number;
    var currentSecondaryColor: number;

    const disableInput = [75, 278, 279, 280, 281, 23, 59, 60, 71, 72, 74];

    const carModTypes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 18, 22, -2, -1, 25, 27, 28, 33, 34, 35, 38, 39, 40, 41, 42, 43, 44, 46, 48, 69];

    const carModSlotName = [
        { Slot: 0, Name: "Spoiler", Price: 1000 },
        { Slot: 1, Name: "Frontstoßstange", Price: 1500 },
        { Slot: 2, Name: "Heckstoßstange", Price: 1500 },
        { Slot: 3, Name: "Seitenschweller", Price: 1500 },
        { Slot: 4, Name: "Auspuff", Price: 500 },
        { Slot: 5, Name: "Rahmen", Price: 1000 },
        { Slot: 6, Name: "Kühlergrill", Price: 1000 },
        { Slot: 7, Name: "Motorhaube", Price: 2000 },
        { Slot: 8, Name: "Extra 1", Price: 2000 },
        { Slot: 9, Name: "Extra 2", Price: 2000 },
        { Slot: 10, Name: "Dach", Price: 1500 },
        { Slot: 11, Name: "Motor", BasePercentage: 20, PriceIncreasePerLevel: 7.5 },
        { Slot: 12, Name: "Bremsen", BasePercentage: 5, PriceIncreasePerLevel: 2.5 },
        { Slot: 13, Name: "Getriebe", BasePercentage: 10, PriceIncreasePerLevel: 2.5 },
        { Slot: 14, Name: "Hupe", Price: 500 },
        { Slot: 15, Name: "Federung", Price: 2000 },
        { Slot: 18, Name: "Turbo", BasePercentage: 45, PriceIncreasePerLevel: 0 },
        { Slot: 22, Name: "Licht", Price: 500 },
        { Slot: -2, Name: "Reifen", Price: 2500 },
        { Slot: -1, Name: "Lackierung", Price: 1000 },
        { Slot: 25, Name: "Nummernschildhalter", Price: 500 },
        { Slot: 27, Name: "Innenausstatung", Price: 500 },
        { Slot: 28, Name: "Wackelkopf", Price: 200 },
        { Slot: 33, Name: "Lenkrad", Price: 300 },
        { Slot: 34, Name: "Schalthebel", Price: 200 },
        { Slot: 35, Name: "Schild", Price: 200 },
        { Slot: 38, Name: "Hydraulik", Price: 2000 },
        { Slot: 39, Name: "Motorabdeckung", Price: 2000 },
        { Slot: 40, Name: "Luftfilter", Price: 1000 },
        { Slot: 41, Name: "Domstrebe", Price: 1000 },
        { Slot: 42, Name: "Scheinwerferabdeckung", Price: 500 },
        { Slot: 43, Name: "Nebelscheinwerfer", Price: 1000 },
        { Slot: 44, Name: "Dach-Extra", Price: 1000 },
        { Slot: 46, Name: "Fenster", Price: 1000 },
        { Slot: 48, Name: "Design", Price: 2000 }
    ];

    const customPartNames = [
        {
            Model: 1093792632,
            Names: [
                {
                    Slot: 8,
                    Name: "Lüftungsschlitze"
                },
                {
                    Slot: 43,
                    Name: "Motorhaubenstifte"
                }
            ]
        },
        {
            Model: 223240013,
            Names: [
                {
                    Slot: 9,
                    Name: "Heckkotflügel"
                }
            ]
        },
        {
            Model: 1031562256,
            Names: [
                {
                    Slot: 5,
                    Name: "Stoßdämpfer"
                }
            ]
        },
        {
            Model: 3308022675,
            Names: [
                {
                    Slot: 9,
                    Name: "Kotflügel"
                }
            ]
        }
    ];

    const doorOpeners = [
        {
            Model: 3308022675,
            Doors: [
                {
                    Slot: 5,
                    Door: 4
                }
            ]
        }
    ];

    const wheelTypes = [
        {
            Name: "Sport",
            Type: 0,
        },
        {
            Name: "Muscle",
            Type: 1,
        },
        {
            Name: "Lowrider",
            Type: 2,
        },
        {
            Name: "SUV",
            Type: 3,
        },
        {
            Name: "Offroad",
            Type: 4,
        },
        {
            Name: "Tuner",
            Type: 5,
        },
        {
            Name: "High End",
            Type: 7,
        },
        {
            Name: "Benny's Originals",
            Type: 8,
        },
        {
            Name: "Benny's Bespoke",
            Type: 9,
        },
        {
            Name: "Street",
            Type: 11,
        }
    ];

    var mainMenu: NativeUI.Menu;

    mp.events.add('showTuningInfo', () => {
        //mp.game.ui.setTextComponentFormat('STRING');
        //mp.game.ui.addTextComponentSubstringPlayerName('Drücke ~INPUT_CONTEXT~, um dein Fahrzeug zu modifizieren');
        //mp.game.ui.displayHelpTextFromStringLabel(0, true, true, -1);

        mp.events.call("renderHelpTextOnScreen", "~s~Drücke ~g~E ~s~um dein Fahrzeug zu modifizieren")

        mp.keys.bind(0x45, false, keyPressHandler);
        keyBound = true;
    });

    mp.events.add('hideTuningInfo', (unbind) => {
        mp.game.ui.clearHelp(true);
        mp.gui.chat.show(true);

        if (mp.players.local.vehicle) {
            mp.players.local.vehicle.setLights(0);
        }

        if (typeof mainMenu !== "undefined" && unbind) {
            mainMenu.Close();
            globalData.InTuning = false;
        }

        if (keyBound && unbind) {
            mp.keys.unbind(0x45, false, keyPressHandler);
            keyBound = false;
        }
    });

    function keyPressHandler() {
        mp.events.callRemote("startPlayerTuning");
    }

    mp.events.add("render", () => {
        if (globalData.InTuning) {
            disableInput.forEach((input) => {
                mp.game.controls.disableControlAction(1, input, true);
            });
        }
    });

    var currentMod = new Array<number>();
    var currentActiveModItem = new Array<NativeUI.UIMenuItem>();
    var currentSelectedItem: VehicleModMenuItem = null;

    mp.events.add("showTuningMenu", (noMoney, basePrice) => {
        mp.events.call("hideTuningInfo", false);
        mp.gui.chat.show(false);

        var localPlayer = mp.players.local;
        var localVehicle = localPlayer.vehicle;

        localVehicle.setHalt(1.0, 1, false);

        globalData.InMenu = true;
        globalData.InTuning = true;

        localVehicle.setLights(1);
        var carName = mp.game.ui.getLabelText(mp.game.vehicle.getDisplayNameFromVehicleModel(localVehicle.model));

        mainMenu = new Menu("Fahrzeugwerkstatt", carName, new Point(0, screenRes.y / 3), null, null);

        var repairItem = new UIMenuItem("Fahrzeug reparieren");
        mainMenu.AddItem(repairItem);
        repairItem.BackColor = new Color(94, 94, 94);
        repairItem.HighlightedBackColor = new Color(105, 105, 105);

        carModTypes.forEach((modType) => {
            var mod: number = null;

            if (modType === 22) { // Lichter
                var hlColor = localVehicle.getVariable("headlightColor");
                if (typeof hlColor !== "number" || isNaN(hlColor) || hlColor < 0 || hlColor === 255) {
                    mod = -1;
                } else if (hlColor === 13) mod = 0;
                else mod = hlColor + 1;
            } else if (modType === 18) { // Turbo
                var toggle = localVehicle.isToggleModOn(modType);
                mod = toggle ? 0 : -1;
            } else if (modType == -1) { // Lackierungen 
                var colorItem = new UIMenuItem("Lackierungen");
                var colorMenu = getColorMenu();

                mainMenu.AddItem(colorItem);
                mainMenu.BindMenuToItem(colorMenu, colorItem);

                return;
            } else if (modType == -2) {
                var wheelsItem = new UIMenuItem("Reifen");
                var wheelsMenu = getWheelsMenu(localVehicle);

                mainMenu.AddItem(wheelsItem);
                mainMenu.BindMenuToItem(wheelsMenu, wheelsItem);
                return;
            }

            var num = localVehicle.getNumMods(modType);

            if (num === 0 && modType !== 18 && modType !== 22 && modType !== -1) return;

            var modName = localVehicle.getModSlotName(modType) || "nix gefunden";
            modName = mp.game.ui.getLabelText(modName);

            if (modName === "NULL") {
                for (var x = 0; x < carModSlotName.length; x++) {
                    var tmpSlot = carModSlotName[x];
                    if (tmpSlot.Slot == modType) {
                        modName = tmpSlot.Name;
                        break;
                    }
                }
            }

            if (mod === null) {
                mod = localVehicle.getMod(modType);
            }

            var modNum = localVehicle.getNumMods(modType);
            if (modType === 18) modNum = 1;
            if (modType === 22) modNum = 14;

            var modMenu = new Menu(modName, carName, new Point(0, screenRes.y / 3), null, null);

            modMenu.Visible = false;

            var menuItem = new UIMenuItem(modName);
            mainMenu.AddItem(menuItem);
            mainMenu.BindMenuToItem(modMenu, menuItem);

            currentMod[modType] = mod;

            for (var x = -1; x < modNum; x++) {
                var price = noMoney ? 0 : getModSlotPrice(modType, basePrice, x);
                var modText = "";
                if (x === -1) {
                    modText = "Serie";
                } else {
                    modText = mp.game.ui.getLabelText(localVehicle.getModTextLabel(modType, x));
                    if (modText === "NULL") modText = getModName(localVehicle, modType, x);
                }
                var item = new VehicleModMenuItem(modText);
                item.price = price;
                modMenu.AddItem(item);

                if (x === mod) {
                    item.SetRightBadge(BadgeStyle.Car);
                    currentActiveModItem[modType] = item;
                    modMenu.CurrentSelection = x;
                }
                else {
                    item.SetRightLabel("$" + moneyformat(price));
                }
            }

            modMenu.IndexChange.on((index: number) => {
                if (modType === 18) return;
                if (modType === 22) {
                    setHeadlightsColor(localVehicle, index);
                    return;
                }
                localVehicle.setMod(modType, index - 1);
            });

            modMenu.MenuOpen.on(() => {
                if (modType === 22) {
                    localVehicle.setLights(2);
                }
            });

            modMenu.ItemSelect.on((item: VehicleModMenuItem, index: number) => {
                if (currentMod[modType] == index - 1) {
                    return;
                }

                currentSelectedItem = item;
                mp.events.callRemote("setVehicleMod", modType, index, price);
            });

            modMenu.MenuClose.on(() => {
                if (modType === 18) return;
                if (modType === 22) {
                    localVehicle.setLights(1);
                    setHeadlightsColor(localVehicle, currentMod[22] + 1);
                    return;
                }
                localVehicle.setMod(modType, currentMod[modType]);
            });
        });

        mainMenu.ItemSelect.on((item: NativeUI.UIMenuItem, index: number) => {
            if (item === repairItem) {
                mp.events.callRemote("repairVehicle");
            };
        });

        mainMenu.Visible = true;

        mainMenu.MenuClose.on(() => {
            if (localVehicle && mp.vehicles.exists(localVehicle)) {
                localVehicle.setLights(0);
            }
            globalData.InTuning = false;
            globalData.InMenu = false;
            mp.events.call("hideTuningInfo", false);
        });

    });

    mp.events.add("SERVER:Tuning_ModSucessfull", (modType: number, index: number) => {
        currentMod[modType] = index - 1;
        currentActiveModItem[modType].SetRightLabel("$" + moneyformat(currentSelectedItem.price));
        currentActiveModItem[modType].SetRightBadge(NativeUI.BadgeStyle.None);
        currentSelectedItem.SetRightBadge(BadgeStyle.Car);
        currentSelectedItem.SetRightLabel("");
        currentActiveModItem[modType] = currentSelectedItem;
    });

    mp.events.add("playerLeaveVehicle", () => {
        if (keyBound) {
            mp.events.call("hideTuningInfo", true);
        }
    });

    function getModName(vehicle: VehicleMp, slot: number, mod: number) {
        var modName = vehicle.getModTextLabel(slot, mod);
        var realModName = mp.game.ui.getLabelText(modName);

        if (slot === 11) {
            switch (mod) {
                case 0:
                    realModName = "EMS Verbesserung 1";
                    break;
                case 1:
                    realModName = "EMS Verbesserung 2";
                    break;
                case 2:
                    realModName = "EMS Verbesserung 3";
                    break;
                case 3:
                    realModName = "EMS Verbesserung 4";
                    break;
            }
        } else if (slot === 12) {
            switch (mod) {
                case 0:
                    realModName = "Straßenbremsen";
                    break;
                case 1:
                    realModName = "Sportbremsen";
                    break;
                case 2:
                    realModName = "Rennbremsen";
                    break;
                case 3:
                    realModName = "Wettkampfbremsen";
                    break;
            }
        } else if (slot === 13) {
            switch (mod) {
                case 0:
                    realModName = "Straßengetriebe";
                    break;
                case 1:
                    realModName = "Sportgetriebe";
                    break;
                case 2:
                    realModName = "Renngetriebe";
                    break;
                case 3:
                    realModName = "Wettkampfgetriebe";
            }
        } else if (slot === 15) {
            switch (mod) {
                case 0:
                    realModName = "Tiefere Federung";
                    break;
                case 1:
                    realModName = "Straßenfederung";
                    break;
                case 2:
                    realModName = "Sportfederung";
                    break;
                case 3:
                    realModName = "Rennfederung";
                    break;
                case 4:
                    realModName = "Wettkampffederung";
                    break;
            }
        } else if (slot === 18) {
            realModName = "Turbotuning";
        } else if (slot === 22) {
            switch (mod) {
                case 0:
                    realModName = "Xenon Licht";
                    break;
                case 1:
                    realModName = "Weißes Licht";
                    break;
                case 2:
                    realModName = "Blaues Licht";
                    break;
                case 3:
                    realModName = "Hell-blaues Licht";
                    break;
                case 4:
                    realModName = "Grünes Licht";
                    break;
                case 5:
                    realModName = "Hell-grünes Licht";
                    break;
                case 6:
                    realModName = "Hell-gelbes Licht";
                    break;
                case 7:
                    realModName = "Gelbes Licht";
                    break;
                case 8:
                    realModName = "Orangenes Licht";
                    break;
                case 9:
                    realModName = "Rotes Licht";
                    break;
                case 10:
                    realModName = "Hell-pinkes Licht";
                    break;
                case 11:
                    realModName = "Pinkes Licht";
                    break;
                case 12:
                    realModName = "Lila Licht";
                    break;
                case 13:
                    realModName = "Schwarzlicht";
                    break;
            }
        }

        return realModName;
    }

    function getModSlotPrice(modType: number, basePrice: number, modIndex?: number): number {
        if (modIndex === -1) {
            return 0;
        }

        let price = 0;
        let priceInfo = carModSlotName.filter(x => x.Slot == modType)[0];

        if (priceInfo.BasePercentage) {
            price = ((priceInfo.BasePercentage + priceInfo.PriceIncreasePerLevel * modIndex) / 100) * basePrice;
        } else {
            price = priceInfo.Price;
        }

        return price;
    }

    function setHeadlightsColor(vehicle, index) {

        if (!vehicle) {
            return;
        }

        var color = index - 2;
        if (index === 0) color = -1;
        if (index === 1) color = 13;
        if (typeof color !== "number" || isNaN(color) || color < 0 || color === 255) {
            // Disable
            vehicle.toggleMod(22, false);
            mp.game.invoke("0xE41033B25D003A07", vehicle.handle, 255);
        } else {
            // Enable
            vehicle.toggleMod(22, true);
            mp.game.invoke("0xE41033B25D003A07", vehicle.handle, color);
        }
    }

    var currentWheelType = null;
    var currentWheel = null;
    var currentWheelItem: NativeUI.UIMenuItem = null;
    var wheelPrice = getModSlotPrice(-2, 0, 0);
    var currentSelectedWheelItem: NativeUI.UIMenuItem = null;

    function getWheelsMenu(vehicle: VehicleMp): NativeUI.Menu {
        var wheelsMenu = new NativeUI.Menu("Reifen", "rollin on dem rims", new NativeUI.Point(0, screenRes.y / 3));

        currentWheelType = vehicle.getWheelType();
        currentWheel = vehicle.getMod(23);
        currentWheelItem = null;

        wheelTypes.forEach(wheelType => {
            var type = wheelType.Type;

            var modsLoaded = false;

            var menuOpenTime: number = null;

            var typeItem = new UIMenuItem(wheelType.Name);
            wheelsMenu.AddItem(typeItem);

            var wheelTypeMenu = new Menu(wheelType.Name, "skyr", new Point(0, screenRes.y / 3));

            wheelsMenu.BindMenuToItem(wheelTypeMenu, typeItem);

            wheelTypeMenu.IndexChange.on((index: number) => {
                vehicle.setMod(23, index);
            });

            wheelTypeMenu.MenuOpen.on(() => {
                menuOpenTime = Date.now();
                vehicle.setWheelType(type);
                if (modsLoaded) {
                    return;
                }

                var wheelNums = vehicle.getNumMods(23);

                for (var i = 0; i < wheelNums; i++) {
                    var modText = "";

                    modText = mp.game.ui.getLabelText(vehicle.getModTextLabel(23, i));
                    if (modText === "NULL") modText = getModName(vehicle, 23, i);

                    var item = new VehicleModMenuItem(modText);

                    if (type == currentWheelType && i == currentWheel) {
                        currentWheelItem = item;
                        currentWheelItem.SetRightBadge(BadgeStyle.Car);
                    } else {
                        item.SetRightLabel("$" + moneyformat(wheelPrice));
                    }

                    wheelTypeMenu.AddItem(item);
                }

                modsLoaded = true;
            });

            wheelTypeMenu.ItemSelect.on((item, index: number) => {
                if (Date.now() - menuOpenTime < 500 || item == currentWheelItem) {
                    return;
                }

                currentSelectedWheelItem = item;
                mp.events.callRemote("CLIENT:Tuning_SetVehicleWheels", type, index, wheelPrice);
            });

            wheelTypeMenu.MenuClose.on(() => {
                vehicle.setWheelType(currentWheelType);
                vehicle.setMod(23, currentWheel);
            })
        });

        return wheelsMenu;
    }

    mp.events.add("SERVER:Tuning_SetWheelsSuccessfull", (type, index) => {
        currentWheelType = type;
        currentWheel = index;

        if (currentWheelItem) {
            currentWheelItem.SetRightLabel("$" + moneyformat(wheelPrice));
            currentWheelItem.SetRightBadge(BadgeStyle.None);
        }

        currentWheelItem = currentSelectedWheelItem;
        currentWheelItem.SetRightBadge(BadgeStyle.Car);
        currentWheelItem.SetRightLabel("");
    })

    function getColorMenu(): NativeUI.Menu {
        var currentColors = mp.players.local.vehicle.getColours(0, 0);

        currentPrimaryColor = currentColors.colorPrimary;
        currentSecondaryColor = currentColors.colorSecondary;

        var primaryColor = getSingleColorMenu("Primärfarbe", currentPrimaryColor, primaryColorSelect, primaryColorChange);
        var secondaryColor = getSingleColorMenu("Sekundärfarbe", currentSecondaryColor, secondaryColorSelect, secondaryColorChange);

        var menu = new Menu("Lackierungen", "Fahrzeugfarbe ändern", new Point(0, screenRes.y / 3));

        var primaryColorItem = new UIMenuItem("Primärfarbe");
        var secondaryColorItem = new UIMenuItem("Sekundärfarbe");

        secondaryColor.MenuClose.on(() => {
            mp.players.local.vehicle.setColours(currentPrimaryColor, currentSecondaryColor);
        });

        primaryColor.MenuClose.on(() => {
            mp.players.local.vehicle.setColours(currentPrimaryColor, currentSecondaryColor);
        });

        menu.AddItem(primaryColorItem);
        menu.AddItem(secondaryColorItem);

        menu.BindMenuToItem(primaryColor, primaryColorItem);
        menu.BindMenuToItem(secondaryColor, secondaryColorItem);

        return menu;
    }

    function getSingleColorMenu(title: string, currentColor: number, onSelect: (color: number) => void, onChange: (color: number) => void): NativeUI.Menu {
        var menu = new Menu(title, "Fahrzeugfarbe ändern", new Point(0, screenRes.y / 3));

        var colorCategories = Object.keys(vehicleColors);

        var currentColorItem: NativeUI.UIMenuItem = null;

        colorCategories.forEach(category => {
            var categoryItem = new UIMenuItem(category);
            menu.AddItem(categoryItem);

            var categoryMenu = new Menu(category, "Fahrzeugfarbe ändern", new Point(0, screenRes.y / 3));

            var categoryColors = Object.keys(vehicleColors[category]);
            categoryColors.forEach(categoryColor => {
                var color = vehicleColors[category][categoryColor];

                var colorItem = new UIMenuItem(categoryColor);
                colorItem.Data = color;

                if (color === currentColor) {
                    colorItem.SetRightBadge(BadgeStyle.Car);
                    currentColorItem = colorItem;
                }

                categoryMenu.AddItem(colorItem);
            });

            menu.BindMenuToItem(categoryMenu, categoryItem);

            categoryMenu.IndexChange.on((index, item: NativeUI.UIMenuItem) => {
                onChange(<number>item.Data);
            });

            categoryMenu.ItemSelect.on((item: NativeUI.UIMenuItem, index: number) => {
                currentColorItem.SetRightBadge(BadgeStyle.None);

                item.SetRightBadge(BadgeStyle.Car);
                currentColorItem = item;

                onSelect(<number>item.Data);
            });
        });

        return menu;
    }

    function primaryColorChange(color: number) {
        mp.players.local.vehicle.setColours(color, currentSecondaryColor);
    }

    function primaryColorSelect(color: number) {
        currentPrimaryColor = color;

        mp.events.callRemote("CLIENT:TuningManager_SetVehicleColor", true, color);
    }

    function secondaryColorChange(color: number) {
        mp.players.local.vehicle.setColours(currentPrimaryColor, color);
    }

    function secondaryColorSelect(color: number) {
        currentSecondaryColor = color;

        mp.events.callRemote("CLIENT:TuningManager_SetVehicleColor", false, color);
    }



    class VehicleModMenuItem extends UIMenuItem {
        public price: number;
    }
}