using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using Godot;
using Godot.Bridge;
using Godot.Collections;
using Godot.NativeInterop;
using Newtonsoft.Json;

[ScriptPath("res://Scripts/UI/Settings.cs")]
public partial class Settings : RichTextLabel
{
    public enum SettingIndex
    {
        MusicVol,
        SFXVol,
        AlwaysRun,
        AutoFire,
        Fullscreen,
        Inputs,
        Return,
        Exit
    }

    private Coroutine doingInputs;

    public static SettingsFile file = new SettingsFile();

    [Export(PropertyHint.None, "")]
    private Sprite2D soul;

    private int option;

    private bool wait;

    private const int max = 7;

    private const string path = "user://Settings.dat";

    private Key? lastKey;

    private int currentKey;

    public override void _EnterTree()
    {
        base.Text = Texts.common[59].Replace("@", "\t") + file.musVol + "%\n" + Texts.common[60].Replace("@", "\t") + file.sfxVol + "%\n" + Texts.common[61].Replace("@", "\t") + (file.run ? "ON" : "OFF") + "\n" + Texts.common[62].Replace("@", "\t") + (file.autoFire ? "ON" : "OFF") + "\n" + Texts.common[63].Replace("@", "\t") + (file.fullScreen ? "ON" : "OFF") + "\n" + Texts.common[64] + "\n" + Texts.common[65] + "\n";
        if (MainMenu.instance == null)
        {
            base.Text += Texts.common[66];
        }
        else
        {
            base.Text += Texts.common[67];
        }
    }

    public override void _Process(double delta)
    {
        Coroutine coroutine = doingInputs;
        if (coroutine != null && coroutine.done)
        {
            doingInputs = null;
        }
        if (doingInputs != null)
        {
            return;
        }
        if (!wait)
        {
            wait = true;
            return;
        }
        soul.Position = new Vector2(-8f, 8 + option * 15);
        if (Input.IsActionJustPressed(Main.keys[0]))
        {
            if (option > 0)
            {
                option--;
            }
            Audio.PlaySound(Audio.commonSounds[0]);
        }
        else if (Input.IsActionJustPressed(Main.keys[1]))
        {
            if (option < 7)
            {
                option++;
            }
            Audio.PlaySound(Audio.commonSounds[0]);
        }
        else if (Input.IsActionJustPressed(Main.keys[2]))
        {
            ToggleSettings(-1);
            Audio.PlaySound(Audio.commonSounds[0]);
        }
        else if (Input.IsActionJustPressed(Main.keys[3]))
        {
            ToggleSettings(1);
            Audio.PlaySound(Audio.commonSounds[0]);
        }
        else if (Input.IsActionJustPressed(Main.keys[4]))
        {
            ToggleSettings(1);
            Audio.PlaySound(Audio.commonSounds[2]);
        }
        else if (Input.IsActionJustPressed(Main.keys[5]))
        {
            Audio.PlaySound(Audio.commonSounds[2]);
            SaveSettings();
            QueueFree();
        }
    }

    private void ToggleSettings(int i)
    {
        switch ((SettingIndex)option)
        {
            case SettingIndex.SFXVol:
                file.sfxVol = Mathf.Clamp(file.sfxVol + i * 10, 0, 100);
                UpdateVolume();
                break;
            case SettingIndex.MusicVol:
                file.musVol = Mathf.Clamp(file.musVol + i * 10, 0, 100);
                UpdateVolume();
                break;
            case SettingIndex.AutoFire:
                file.autoFire = !file.autoFire;
                break;
            case SettingIndex.Exit:
                SaveSettings();
                if (MainMenu.instance == null)
                {
                    CameraController.instance.GlobalPosition = Vector2.Zero;
                    GetTree().ReloadCurrentScene();
                }
                else
                {
                    GetTree().Quit();
                }
                break;
            case SettingIndex.Inputs:
                doingInputs = Coroutine.Start(InputRebind());
                break;
            case SettingIndex.Return:
                SaveSettings();
                QueueFree();
                break;
            case SettingIndex.AlwaysRun:
                file.run = !file.run;
                break;
            case SettingIndex.Fullscreen:
                file.fullScreen = !file.fullScreen;
                break;
        }
        _EnterTree();
    }

    public static void SaveSettings()
    {
        FileAccess fileAccess = FileAccess.Open("user://Settings.dat", FileAccess.ModeFlags.Write);
        fileAccess.StoreString(JsonConvert.SerializeObject(file));
        fileAccess.Close();
        ApplySettings();
    }

    public override void _Input(InputEvent @event)
    {
        if (doingInputs != null && !lastKey.HasValue && @event is InputEventKey inputEventKey)
        {
            if (SettingsFile.allowed.Contains(inputEventKey.Keycode))
            {
                lastKey = inputEventKey.Keycode;
            }
            else
            {
                Audio.PlaySound(Audio.commonSounds[1]);
            }
        }
    }

    private IEnumerator InputRebind()
    {
        int[] k = new int[8] { 68, 69, 70, 71, 72, 73, 74, 90 };
        soul.Visible = false;
        base.Text = "";
        while (Input.IsAnythingPressed())
        {
            yield return null;
        }
        yield return null;
        lastKey = null;
        for (int currentKey = 0; currentKey < k.Length; currentKey++)
        {
            Array<InputEvent> array = InputMap.ActionGetEvents(Main.keys[currentKey]);
            base.Text = Texts.common[75].Replace("@", "\n" + Texts.common[k[currentKey]]) + "\n" + Texts.common[94].Replace("#", ((InputEventKey)array[0]).Keycode.ToString()) + "\n" + Texts.common[76] + "\n\n" + Texts.common[95].Replace("@", "\n");
            while (true)
            {
                if (Input.IsActionJustPressed(Main.keys[8]))
                {
                    while (Input.IsAnythingPressed())
                    {
                        yield return null;
                    }
                    break;
                }
                if (lastKey.HasValue)
                {
                    file.keys[currentKey] = lastKey.Value;
                    while (Input.IsAnythingPressed())
                    {
                        yield return null;
                    }
                    lastKey = null;
                    break;
                }
                yield return null;
            }
        }
        soul.Visible = true;
        UpdateKeys();
        _EnterTree();
    }

    public static void UpdateKeys()
    {
        for (int i = 0; i < 8; i++)
        {
            ((InputEventKey)InputMap.ActionGetEvents(Main.keys[i])[0]).Keycode = file.keys[i];
        }
    }

    public static void LoadSettings()
    {
        if (FileAccess.FileExists("user://Settings.dat"))
        {
            try
            {
                FileAccess fileAccess = FileAccess.Open("user://Settings.dat", FileAccess.ModeFlags.Read);
                file = JsonConvert.DeserializeObject<SettingsFile>(fileAccess.GetAsText());
                fileAccess.Close();
            }
            catch
            {
                GD.Print("Settings file invalid, skipping...");
            }
        }
        ApplySettings();
    }

    private static void ApplySettings()
    {
        try
        {
            UpdateVolume();
            UpdateKeys();
            UpdateWindow();
        }
        catch
        {
            GD.Print("Settings file invalid, skipping...");
        }
    }

    public static void UpdateWindow()
    {
        if (!Engine.IsEmbeddedInEditor())
        {
            if (file.fullScreen)
            {
                Main.tree.Root.ContentScaleStretch = Window.ContentScaleStretchEnum.Fractional;
                DisplayServer.WindowSetMode(DisplayServer.WindowMode.Fullscreen);
                return;
            }
            Main.tree.Root.ContentScaleStretch = Window.ContentScaleStretchEnum.Integer;
            DisplayServer.WindowSetMode(DisplayServer.WindowMode.Windowed);
            DisplayServer.WindowSetSize(new Vector2I(641, 480));
            Window window = Main.instance.GetWindow();
            Rect2I rect2I = DisplayServer.ScreenGetUsableRect(window.CurrentScreen);
            Vector2I sizeWithDecorations = window.GetSizeWithDecorations();
            window.Position = rect2I.Position + (rect2I.Size / 2 - sizeWithDecorations / 2);
            DisplayServer.WindowSetSize(new Vector2I(768, 480));
        }
    }

    private static void UpdateVolume()
    {
        AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Music"), Mathf.LinearToDb((float)file.musVol / 100f));
        AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Sound"), Mathf.LinearToDb((float)file.sfxVol / 100f));
    }

}