using Godot;
using System;

public partial class input_menu : CenterContainer
{
    //public CenterContainer Menu;
    private string awaitingAction;
    private Label awaitingLabel;
    private Button awaitingButton;
    
    private Button _inpFwd;
    private Button _inpBack;
    private Button _inpLeft;
    private Button _inpRight;
    private Button _inpSR;
    private Button _inpSL;
    private Button _inpShoot;
    private Button _inpFA;
    private Button _inpPause;
    
    private bool _buttonInit = false;
    
    public override void _Ready()
    {
        awaitingLabel = GetNode<Label>("Layout/ListenLabel");
        awaitingLabel.Text = "";
        
        GetNode<Button>("Layout/Back").Pressed += HideInputPanel;
        GetNode<Button>("Layout/Save").Hide(); // hide save button - not needed really.
        
        //input buttons
        _inpFwd = GetNode<Button>("Layout/Forward/InpFwd");
        _inpBack = GetNode<Button>("Layout/Backward/InpBack");
        _inpLeft = GetNode<Button>("Layout/Left/InpLeft");
        _inpRight = GetNode<Button>("Layout/Right/InpRight");
        _inpSR = GetNode<Button>("Layout/StrafeR/InpSR");
        _inpSL = GetNode<Button>("Layout/StrafeL/InpSL");
        _inpShoot = GetNode<Button>("Layout/Shoot/InpShoot");
        _inpFA = GetNode<Button>("Layout/Flight Assist/InpFA");
        _inpPause = GetNode<Button>("Layout/Pause/InpPause");
        
        _inpFwd.Pressed += () => StartRebind("up", _inpFwd);
        _inpBack.Pressed += () => StartRebind("down", _inpBack);
        _inpLeft.Pressed += () => StartRebind("left", _inpLeft);
        _inpRight.Pressed += () => StartRebind("right", _inpRight);
        _inpSR.Pressed += () => StartRebind("strafe_right", _inpSR);
        _inpSL.Pressed += () => StartRebind("strafe_left", _inpSL);
        _inpShoot.Pressed += () => StartRebind("shoot", _inpShoot);
        _inpFA.Pressed += () => StartRebind("toggle_fa", _inpFA);
        _inpPause.Pressed += () => StartRebind("pause", _inpPause);
        //LoadInputConfig();
        //UpdateButtonText();
    }

    public override void _Process(double delta)
    {
        if (Visible && _buttonInit)
        {
            LoadInputConfig();
            UpdateButtonText();
            _buttonInit = true;
        }
    }

    private void UpdateButtonText()
    {
        _inpFwd.Text = GetKey("up");
        _inpBack.Text = GetKey("down");
        _inpLeft.Text = GetKey("left");
        _inpRight.Text = GetKey("right");
        _inpSR.Text = GetKey("strafe_right");
        _inpSL.Text = GetKey("strafe_left");
        _inpShoot.Text = GetKey("shoot");
        _inpFA.Text = GetKey("toggle_fa");
        _inpPause.Text = GetKey("pause");
    }

    private static string GetKey(string action)
    {
        var config = new ConfigFile();
        var err = config.Load("user://config/input.cfg");
        if (err != Error.Ok)
            return "-";

        int keycode = (int)config.GetValue("Input", action, 0);
        if (keycode == 0)
            return "-";

        return OS.GetKeycodeString((Key)keycode);
    }

    private void SaveInputConfig(string path = "user://config/input.cfg")
    {
        var config = new ConfigFile();
        config.SetValue("Input", "up", GetActionKeycode("up"));
        config.SetValue("Input", "down", GetActionKeycode("down"));
        config.SetValue("Input", "left", GetActionKeycode("left"));
        config.SetValue("Input", "right", GetActionKeycode("right"));
        config.SetValue("Input", "strafe_right", GetActionKeycode("strafe_right"));
        config.SetValue("Input", "strafe_left", GetActionKeycode("strafe_left"));
        config.SetValue("Input", "shoot", GetActionKeycode("shoot"));
        config.SetValue("Input", "toggle_fa", GetActionKeycode("toggle_fa"));
        config.SetValue("Input", "pause", GetActionKeycode("pause"));
        config.Save(path);
    }

    private static void LoadInputConfig(string path = "user://config/input.cfg")
    {
        var config = new ConfigFile();
        var err = config.Load(path);
        if (err != Error.Ok)
        {
            //GD.Print("Failed to load input config");
            return;
        }

        string[] actions = {"up", "down", "left", "right", "strafe_left", "strafe_right", "shoot", "toggle_fa", "pause"};

        foreach (var action in actions)
        {
            InputMap.ActionEraseEvents(action);

            int keycode = (int)config.GetValue("Input", action, 0);
            //GD.Print(keycode);
            if (keycode != 0)
            {
                var ev = new InputEventKey();
                ev.Keycode = (Key)keycode;
                ev.PhysicalKeycode = (Key)keycode;
                InputMap.ActionAddEvent(action, ev);
                //UpdateButtonText();
            }
        }
    }

    private static int GetActionKeycode(string action)
    {
        foreach (var e in InputMap.ActionGetEvents(action))
        {
            if (e is InputEventKey key) return (int)key.Keycode;
        }
        return 0;
    }

    public void ShowInputPanel()
    {
     this.Visible = true;
     UpdateButtonText();
    }

    public void HideInputPanel()
    {
        this.Visible = false;
    }

    private void StartRebind(string action, Button button)
    {
        awaitingLabel.Text = "Listening...";
        awaitingAction = action;
        awaitingButton = button;
        
    }

    public override void _Input(InputEvent @event)
    {
        if (awaitingAction == null) return;

        if (@event is not InputEventKey { Pressed: true, Echo: false } eventKey) return;
        if (eventKey.Keycode == Key.Escape)
        {
            awaitingAction = null;
            awaitingLabel.Text = "";
            awaitingButton = null;
            return;
        }
            
        InputMap.ActionEraseEvents(awaitingAction);
        InputMap.ActionAddEvent(awaitingAction, eventKey);

        awaitingButton.Text = eventKey.Keycode.ToString();
        awaitingLabel.Text = "";
        awaitingAction = null;
        awaitingButton = null;
            
        SaveInputConfig();
    }
    
}
