const RU = Resources;
const MM = ModelManager;
const MCU = MinecraftClient;
include(Resources.id("aphrodite:library/code/util/error_supplier.js"));
include(Resources.id("aphrodite:library/code/gui/orderly_responder.js"));

// Load models
const MODELS = ModelManager.loadPartedRawModel(RU.manager(), RU.id("mtrsteamloco:eyecandies/signals/main2.obj"), null);
const MODELRI = ModelManager.loadPartedRawModel(RU.manager(), RU.id("mtrsteamloco:eyecandies/signals/ri_base.obj"), null);

const BASE = ModelManager.uploadVertArrays(MODELS.get("base"));
const BACK = ModelManager.uploadVertArrays(MODELS.get("back_board"));
const VISOR = ModelManager.uploadVertArrays(MODELS.get("visor"));
const LONGVISOR = ModelManager.uploadVertArrays(MODELS.get("visor_long"));
const NOVISOR = ModelManager.uploadVertArrays(MODELS.get("no_visor"));
const MAING = ModelManager.uploadVertArrays(MODELS.get("m_g"));
const MAINR = ModelManager.uploadVertArrays(MODELS.get("m_r"));
const MAINOFF = ModelManager.uploadVertArrays(MODELS.get("m_off"));
const DISTG = ModelManager.uploadVertArrays(MODELS.get("d_g"));
const DISTY = ModelManager.uploadVertArrays(MODELS.get("d_y"));
const DISTOFF = ModelManager.uploadVertArrays(MODELS.get("d_off"));
const ENDY = ModelManager.uploadVertArrays(MODELS.get("e_y"));
const ENDR = ModelManager.uploadVertArrays(MODELS.get("e_r"));
const ENDOFF = ModelManager.uploadVertArrays(MODELS.get("e_off"));
const RI_BASE = ModelManager.uploadVertArrays(MODELRI.get("ri_base_2"));
// Setup config responders
const nodePosKey = "custom"
const typeKey = "typeKey";
const modeKey = "modeKey";
const selectLightKey = "selectLightKey";
const visortype = "visortype"
const hasbackboard = "hasbackboard"
const routeindicatorbase = "0"

const VISORTYPE = new ConfigResponder.TextField(
    visortype,
    ComponentUtil.translatable("signal.visor.type"),
    "1"
).setErrorSupplier(str => {
    if (!["0", "1", "2"].includes(str)) {
        return Optional.of(ComponentUtil.translatable("error.aph.invalid_value"));
    }
    return Optional.empty();
}).setTooltipSupplier(str => Optional.of(asJavaArray([ComponentUtil.translatable("0-no visor 1-standard visor 2-extended visor")], Component)));

const RI = new ConfigResponder.TextField(
    routeindicatorbase,
    ComponentUtil.translatable("route indicator base"),
    "0"
).setErrorSupplier(str => {
    if (!["0", "1"].includes(str)) {
        return Optional.of(ComponentUtil.translatable("error.aph.invalid_value"));
    }
    return Optional.empty();
}).setTooltipSupplier(str => Optional.of(asJavaArray([ComponentUtil.translatable("has route indicator base? (1/0)")], Component)));

const BACKBOARD = new ConfigResponder.TextField(
    hasbackboard,
    ComponentUtil.translatable("backboard"),
    "1"
).setErrorSupplier(str => {
    if (!["0", "1"].includes(str)) {
        return Optional.of(ComponentUtil.translatable("error.aph.invalid_value"));
    }
    return Optional.empty();
}).setTooltipSupplier(str => Optional.of(asJavaArray([ComponentUtil.translatable("has backboard? (1/0)")], Component)));

const nodePosINPUT = new ConfigResponder.TextField(
    nodePosKey, 
    ComponentUtil.literal("Node Pos (x,y,z)"), 
    ""
).setTooltipSupplier(str => Optional.of(asJavaArray([
            ComponentUtil.literal("Leave empty to auto-detect."),
            ComponentUtil.literal("Format: x,y,z)")
        ], Component)))
        .setErrorSupplier(str => {
            if (!str) return Optional.empty();
            const parts = str.split(",");
            if (parts.length !== 3 || parts.some(p => isNaN(parseFloat(p)))) {
                return Optional.of(ComponentUtil.literal("Invalid format. Use x,y,z."));
            }
            return Optional.empty();
        })

const TYPE_RESPONDER = new ConfigResponder.TextField(
    typeKey,
    ComponentUtil.translatable("name.signal.type"),
    "0"
).setErrorSupplier(str => {
    if (!["0", "1", "2"].includes(str)) {
        return Optional.of(ComponentUtil.translatable("error.aph.invalid_value"));
    }
    return Optional.empty();
}).setTooltipSupplier(str => Optional.of(asJavaArray([ComponentUtil.translatable("0-main 1-distance(node pos essential) 2-end of track")], Component)));

const MODE_RESPONDER = new ConfigResponder.TextField(
    modeKey,
    ComponentUtil.translatable("name.signal.mode"),
    "0"
).setErrorSupplier(str => {
    if (!["0", "1"].includes(str)) {
        return Optional.of(ComponentUtil.translatable("error.aph.invalid_value"));
    }
    return Optional.empty();
}).setTooltipSupplier(str => Optional.of(asJavaArray([ComponentUtil.translatable("0-auto 1-manual")], Component)));


const LIGHT_RESPONDER = new ConfigResponder.TextField(
    selectLightKey,
    ComponentUtil.translatable("name.raf.select_light"),
    "off"
).setErrorSupplier(str => {
    if (!["clr","occ","off"].includes(str)) {
        return Optional.of(ComponentUtil.translatable("error.aph.invalid_value"));
    }
    return Optional.empty();
}).setTooltipSupplier(str => Optional.of(asJavaArray([ComponentUtil.translatable("clr-clear occ-occupied off-off")], Component)));

const RESS = orderlyResponder("GeneralLight", "Made by Aphrodite281", [MODE_RESPONDER, LIGHT_RESPONDER,nodePosINPUT,RI,BACKBOARD,VISORTYPE,TYPE_RESPONDER]);

function create(ctx, state, entity) {
    entity.registerCustomConfig(RESS);
    entity.sendUpdateC2S();
}

function render(ctx, state, entity) {
    let mat = new Matrices();
    mat.translate(0, 0, 0.2); // Slight lift
    ctx.drawModel(BASE, mat);

    let mode = entity.getCustomConfig(modeKey) + "";
    let type = entity.getCustomConfig(typeKey) + "";
    let selectedLight = entity.getCustomConfig(selectLightKey) + "";
    let backboard = entity.getCustomConfig(hasbackboard) + "";
    let visor = entity.getCustomConfig(visortype) + "";
    let ri = entity.getCustomConfig(routeindicatorbase) + "";

if (backboard === "1")
    {  
    ctx.drawModel(BACK, mat);
    }
if (ri === "1")
    {  
    ctx.drawModel(RI_BASE, mat);
    }

if (visor === "0")
    {  
    ctx.drawModel(NOVISOR, mat);
    } else if (visor === "2"){
        ctx.drawModel(LONGVISOR, mat);
    } else {ctx.drawModel(VISOR, mat);}

    let oa = -1;
    try {
        let pos = entity.getWorldPosVector3f();
        let facing = entity.getBlockYRot() + entity.rotateY / Math.PI * 180 + 90;
        let nodePosStr = entity.getCustomConfig(nodePosKey);
let nodePos;

if (nodePosStr && nodePosStr.trim() !== "") {
    const parts = nodePosStr.split(",").map(Number);
    if (parts.length === 3 && parts.every(n => !isNaN(n))) {
        nodePos = new Vector3f(parts[0], parts[1], parts[2]);
    }
}

if (!nodePos) {
    nodePos = MCU.getNodeAt(pos, facing);
}
        oa = MCU.getOccupiedAspect(nodePos, facing, 4); // 4 possible aspects
    } catch (e) {}

    // Decide which model to draw
    let modelToDraw = null;
    if (mode === "0"){
        if (type === "0") {
            if (oa === 0) modelToDraw = MAING;
            else if (oa === 1) modelToDraw = MAINR;
            else if (oa === 2) modelToDraw = MAING;
            else if (oa === 3) modelToDraw = MAING;
            else modelToDraw = MAINOFF;
        } else if (type === "1") {
            if (oa === 0) modelToDraw = DISTG;
            else if (oa === 1) modelToDraw = DISTY;
            else if (oa === 2) modelToDraw = DISTG;
            else if (oa === 3) modelToDraw = DISTG;
            else modelToDraw = DISTOFF;
        } else if (type === "2") {
            if (oa === 0) modelToDraw = ENDY;
            else if (oa === 1) modelToDraw = ENDR;
            else if (oa === 2) modelToDraw = ENDY;
            else if (oa === 3) modelToDraw = ENDY;
            else modelToDraw = ENDOFF;
    } 
    }
    else if (mode === "1"){
        if (selectedLight === "clr"){
            if (type === "0") modelToDraw = MAING;
            else if (type === "1") modelToDraw = DISTG;
            else if (type === "2") modelToDraw = ENDY;
        }
        else if (selectedLight === "occ"){
            if (type === "0") modelToDraw = MAINR;
            else if (type === "1") modelToDraw = DISTY;
            else if (type === "2") modelToDraw = ENDR;
        }
        else {
            if (type === "0") modelToDraw = MAINOFF;
            else if (type === "1") modelToDraw = DISTOFF;
            else if (type === "2") modelToDraw = ENDOFF;
        }

    }
    if (modelToDraw != null) {
        ctx.drawModel(modelToDraw, mat);
    }
}
