using UnityEngine;
using Oxide.Core.Libraries.Covalence;
using System.Collections.Generic;
using Oxide.Core;
using Oxide.Game.Rust.Cui;

namespace Oxide.Plugins
{
    [Info("Sound FX", "Lincoln", "2.0.2")]
    [Description("Simulate various Rust sound effects")]

    /* Fixed in 2.0.2:
     * - Cast (string) added to arg.Args[0] to fix CS0266 implicit conversion from Facepunch.StringView to string.
     */
    class SoundFX : RustPlugin
    {
        private const string permUse = "soundfx.use";
        private const string permBypassCooldown = "soundfx.bypasscooldown.use";
        private readonly Hash<string, float> cooldowns = new Hash<string, float>();

        #region Variables
        private List<string> ricochetEffects = new List<string>()
        {
            "assets/bundled/prefabs/fx/ricochet/ricochet1.prefab",
            "assets/bundled/prefabs/fx/ricochet/ricochet2.prefab",
            "assets/bundled/prefabs/fx/ricochet/ricochet3.prefab",
            "assets/bundled/prefabs/fx/ricochet/ricochet4.prefab",
        };

        string explosion = "assets/bundled/prefabs/fx/explosions/explosion_03.prefab";
        string vomit = "assets/bundled/prefabs/fx/gestures/drink_vomit.prefab";
        string landmine = "assets/bundled/prefabs/fx/weapons/landmine/landmine_explosion.prefab";
        string scream = "assets/bundled/prefabs/fx/player/beartrap_scream.prefab";
        string fallDamage = "assets/bundled/prefabs/fx/player/fall-damage.prefab";
        string howl = "assets/bundled/prefabs/fx/player/howl.prefab";
        string lick = "assets/bundled/prefabs/fx/gestures/lick.prefab";
        string headshot = "assets/bundled/prefabs/fx/headshot_2d.prefab";
        string chatter = "assets/prefabs/npc/scientist/sound/chatter.prefab";
        string slurp = "assets/bundled/prefabs/fx/gestures/drink_tea.prefab";

        string fish = "assets/prefabs/misc/decor_dlc/huntingtrophy_fish/effects/hunting-trophy-fish-song.prefab";

        string horn = "assets/content/nexus/ferry/effects/nexus-ferry-departure-horn.prefab";
        string roar = "assets/rust.ai/agents/bear/sound/roar.prefab";
        string zipper = "assets/prefabs/deployable/locker/sound/equip_zipper.prefab";
        string bearTrap = "assets/prefabs/deployable/bear trap/effects/bear-trap-deploy.prefab";
        string scientistDeath = "assets/prefabs/npc/scientist/sound/death.prefab";
        string bullseye = "assets/prefabs/deployable/reactive target/effects/bullseye.prefab";
        string test = "assets/prefabs/npc/murderer/sound/breathing.prefab"; //for testing purposes only
        #endregion

        #region PluginConfig
        //Creating a config file
        private static PluginConfig config;
        private class PluginConfig
        {
            public float maxCooldown { get; set; }
            public float maxRadius { get; set; }


            public static PluginConfig DefaultConfig() => new PluginConfig()
            {
                maxCooldown = 5,
                maxRadius = 5
            };

        }
        protected override void LoadDefaultConfig()
        {
            PrintWarning("New configuration file created.");
            config = PluginConfig.DefaultConfig();
        }
        protected override void LoadConfig()
        {
            base.LoadConfig();
            config = Config.ReadObject<PluginConfig>();
            SaveConfig();
        }
        protected override void SaveConfig()
        {
            Config.WriteObject(config);
        }
        #endregion

        #region Permissions
        private void Init()
        {
            permission.RegisterPermission(permUse, this);
            permission.RegisterPermission(permBypassCooldown, this);
        }
        #endregion

        private bool hasPermission(BasePlayer player)
        {
            if (!permission.UserHasPermission(player.UserIDString, permUse))
            {
                ChatMessage(player, "NoPerm");
                return false;
            }
            return true;
        }

        bool OnCoolDown(BasePlayer player)
        {
            if (permission.UserHasPermission(player.UserIDString, permBypassCooldown)) return false;

            if (!cooldowns.ContainsKey(player.UserIDString))
            {
                cooldowns.Add(player.UserIDString, 0f);
            }

            if (config.maxCooldown > 0 && cooldowns[player.UserIDString] + config.maxCooldown > Interface.Oxide.Now)
            {
                ChatMessage(player, "Cooldown", config.maxCooldown);
                foreach (KeyValuePair<string, float> kvp in cooldowns) Puts("Key: {0}, Value: {1}", kvp.Key, kvp.Value);
                return true;
            }
            cooldowns[player.UserIDString] = Interface.Oxide.Now;
            return false;
        }

        #region Commands
        [ChatCommand("fxmenu")]
        private void FxMenuCommand(BasePlayer player, string command, string[] args)
        {
            if (player == null || !hasPermission(player)) return;
            OpenSoundMenu(player);
        }

        [ChatCommand("fx")]
        private void fxCommand(BasePlayer player, string command, string[] args)
        {
            if (player == null || !hasPermission(player)) return;

            if (args.IsNullOrEmpty())
            {
                OpenSoundMenu(player);
                return;
            }

            if (OnCoolDown(player))
            {
                return;
            }

            Vector3 pos = player.transform.position + UnityEngine.Random.insideUnitSphere * config.maxRadius;

            switch (args[0].ToLower())
            {
                case "ricochet":
                    SendEffect(ricochetEffects.GetRandom(), pos);
                    break;

                case "scream":
                    SendEffect(scream, pos);
                    break;

                case "explosion":
                    SendEffect(explosion, pos);
                    break;

                case "vomit":
                    SendEffect(vomit, pos);
                    break;

                case "slurp":
                    SendEffect(slurp, pos);
                    break;

                case "landmine":
                    SendEffect(landmine, pos);
                    break;

                case "fall":
                    SendEffect(fallDamage, pos);
                    break;

                case "howl":
                    SendEffect(howl, pos);
                    break;

                case "lick":
                    SendEffect(lick, pos);
                    break;

                case "headshot":
                    SendEffect(headshot, pos);
                    break;

                case "chatter":
                    SendEffect(chatter, pos);
                    break;

                case "help":
                    ChatMessage(player, "Help");
                    break;

                case "test":
                    SendEffect(test, pos);
                    break;

                case "fish":
                    SendEffect(fish, pos);
                    break;
                case "horn":
                    SendEffect(horn, player.transform.position);
                    break;
                case "roar":
                    SendEffect(roar, pos);
                    break;
                case "zipper":
                    SendEffect(zipper, pos);
                    break;
                case "beartrap":
                case "trap":
                    SendEffect(bearTrap, pos);
                    break;
                case "scdeath":
                    SendEffect(scientistDeath, pos);
                    break;
                case "bullseye":
                    SendEffect(bullseye, pos);
                    break;

                default:
                    ChatMessage(player, "Invalid");
                    break;
            }
        }

        #endregion

        #region Helpers
        private void SendEffect(string prefabName, Vector3 pos) => Effect.server.Run(prefabName, pos);
        #endregion

        #region GUI
        private void OpenSoundMenu(BasePlayer player)
        {
            CuiHelper.DestroyUi(player, "SoundFXMenu");

            var container = new CuiElementContainer();

            // Outer blur/shadow container
            container.Add(new CuiPanel
            {
                Image = { Color = "0 0 0 0.4" },
                RectTransform = { AnchorMin = "0.3 0.35", AnchorMax = "0.7 0.75" },
                CursorEnabled = true
            }, "Overlay", "SoundFXMenu");

            // Main background with dark theme
            container.Add(new CuiPanel
            {
                Image = { Color = "0.11 0.11 0.13 0.98" },
                RectTransform = { AnchorMin = "0.01 0.01", AnchorMax = "0.99 0.99" }
            }, "SoundFXMenu", "SoundFXMenu.Inner");

            // Header bar
            container.Add(new CuiPanel
            {
                Image = { Color = "0.15 0.15 0.18 1" },
                RectTransform = { AnchorMin = "0 0.88", AnchorMax = "1 1" }
            }, "SoundFXMenu.Inner", "SoundFXMenu.Header");

            // Accent line under header
            container.Add(new CuiPanel
            {
                Image = { Color = "0.9 0.6 0.2 1" },
                RectTransform = { AnchorMin = "0 0", AnchorMax = "1 0.03" }
            }, "SoundFXMenu.Header");

            // Title
            container.Add(new CuiLabel
            {
                Text = { Text = "SOUND FX BOARD", FontSize = 20, Align = TextAnchor.MiddleLeft, Color = "0.95 0.95 0.95 1", Font = "robotocondensed-bold.ttf" },
                RectTransform = { AnchorMin = "0.03 0.03", AnchorMax = "0.85 0.97" }
            }, "SoundFXMenu.Header");

            // Close button
            container.Add(new CuiPanel
            {
                Image = { Color = "0.85 0.25 0.25 1" },
                RectTransform = { AnchorMin = "0.94 0.15", AnchorMax = "0.985 0.85" }
            }, "SoundFXMenu.Header", "SoundFXMenu.CloseBtn");

            container.Add(new CuiLabel
            {
                Text = { Text = "X", FontSize = 18, Align = TextAnchor.MiddleCenter, Color = "1 1 1 1", Font = "robotocondensed-bold.ttf" },
                RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }
            }, "SoundFXMenu.CloseBtn");

            container.Add(new CuiButton
            {
                Button = { Color = "0 0 0 0", Command = "soundfx.close" },
                RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
                Text = { Text = "" }
            }, "SoundFXMenu.CloseBtn");

            // Define sound buttons with emojis and colors (alphabetically ordered)
            var sounds = new List<(string name, string command, string emoji, string color)>
            {
                ("Bear Roar", "roar", "🐻", "0.6 0.3 0.2 1"),
                ("Bear Trap", "beartrap", "🪤", "0.5 0.3 0.3 1"),
                ("Bullseye", "bullseye", "🎯", "0.8 0.1 0.3 1"),
                ("Chatter", "chatter", "📻", "0.4 0.6 0.8 1"),
                ("Explosion", "explosion", "💥", "0.9 0.4 0.1 1"),
                ("Fall Damage", "fall", "🦴", "0.7 0.5 0.4 1"),
                ("Ferry Horn", "horn", "🚢", "0.5 0.6 0.7 1"),
                ("Fish Song", "fish", "🐟", "0.3 0.7 0.9 1"),
                ("Headshot", "headshot", "🎯", "0.9 0.1 0.1 1"),
                ("Landmine", "landmine", "💣", "0.8 0.3 0.1 1"),
                ("Lick", "lick", "👅", "0.9 0.5 0.6 1"),
                ("Ricochet", "ricochet", "🎯", "0.7 0.7 0.7 1"),
                ("Scream", "scream", "😱", "0.8 0.2 0.2 1"),
                ("Sci Death", "scdeath", "💀", "0.7 0.2 0.2 1"),
                ("Slurp", "slurp", "☕", "0.6 0.4 0.2 1"),
                ("Vomit", "vomit", "🤢", "0.4 0.7 0.3 1"),
                ("Wolf Howl", "howl", "🐺", "0.5 0.5 0.7 1"),
                ("Zipper", "zipper", "🤐", "0.6 0.6 0.7 1")
            };

            float startY = 0.84f;
            float buttonHeight = 0.11f;
            float spacing = 0.01f;
            int columns = 3;
            float columnWidth = 0.28f;
            float columnSpacing = 0.03f;

            for (int i = 0; i < sounds.Count; i++)
            {
                int row = i / columns;
                int col = i % columns;
                
                float minX = 0.05f + (col * (columnWidth + columnSpacing));
                float maxX = minX + columnWidth;
                float minY = startY - (row * (buttonHeight + spacing));
                float maxY = minY - buttonHeight;

                var sound = sounds[i];

                // Button
                container.Add(new CuiButton
                {
                    Button = {
                        Command = $"soundfx.play {sound.command}",
                        Color = sound.color
                    },
                    RectTransform = {
                        AnchorMin = $"{minX} {maxY}",
                        AnchorMax = $"{maxX} {minY}"
                    },
                    Text = {
                        Text = $"{sound.emoji} {sound.name}",
                        FontSize = 12,
                        Align = TextAnchor.MiddleCenter,
                        Color = "1 1 1 1",
                        Font = "robotocondensed-bold.ttf"
                    }
                }, "SoundFXMenu.Inner");
            }

            CuiHelper.AddUi(player, container);
        }

        [ConsoleCommand("soundfx.play")]
        private void PlaySoundConsoleCommand(ConsoleSystem.Arg arg)
        {
            var player = arg.Player();
            if (player == null || !hasPermission(player)) return;

            if (OnCoolDown(player))
            {
                return;
            }

            string soundName = (string)arg.Args[0];
            Vector3 pos = player.transform.position + UnityEngine.Random.insideUnitSphere * config.maxRadius;

            switch (soundName)
            {
                case "ricochet": SendEffect(ricochetEffects.GetRandom(), pos); break;
                case "scream": SendEffect(scream, pos); break;
                case "explosion": SendEffect(explosion, pos); break;
                case "vomit": SendEffect(vomit, pos); break;
                case "slurp": SendEffect(slurp, pos); break;
                case "landmine": SendEffect(landmine, pos); break;
                case "fall": SendEffect(fallDamage, pos); break;
                case "howl": SendEffect(howl, pos); break;
                case "lick": SendEffect(lick, pos); break;
                case "headshot": SendEffect(headshot, pos); break;
                case "chatter": SendEffect(chatter, pos); break;
                case "fish": SendEffect(fish, pos); break;
                case "horn": SendEffect(horn, player.transform.position); break;
                case "roar": SendEffect(roar, pos); break;
                case "zipper": SendEffect(zipper, pos); break;
                case "beartrap": SendEffect(bearTrap, pos); break;
                case "scdeath": SendEffect(scientistDeath, pos); break;
                case "bullseye": SendEffect(bullseye, pos); break;
            }
        }

        [ConsoleCommand("soundfx.close")]
        private void CloseSoundMenuConsoleCommand(ConsoleSystem.Arg arg)
        {
            var player = arg.Player();
            if (player == null) return;
            CuiHelper.DestroyUi(player, "SoundFXMenu");
        }
        #endregion

        #region Localization

        private void ChatMessage(BasePlayer player, string messageName, params object[] args) =>
            player.ChatMessage(string.Format(GetMessage(player.UserIDString, messageName), args));

        private string GetMessage(IPlayer player, string messageName, params object[] args) =>
            GetMessage(player.Id, messageName, args);

        private string GetMessage(string playerId, string messageName, params object[] args)
        {
            var message = lang.GetMessage(messageName, this, playerId);
            return args.Length > 0 ? string.Format(message, args) : message;
        }

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["Help"] = "<size=18 ><color=#ffc34d>SoundFX</color></size>" +
                "\n<color=#00ff00>/fx or /fxmenu - Open the Sound FX GUI</color>" +
                "\n<color=#9999ff>/fx ricochet</color> Bullet ricochet." +
                "\n<color=#9999ff>/fx scream</color> Wounded scream." +
                "\n<color=#9999ff>/fx explosion</color> Grenade explosion." +
                "\n<color=#9999ff>/fx slurp</color> Slurping sound effect." +
                "\n<color=#9999ff>/fx vomit</color> Vomit sound effect." +
                "\n<color=#9999ff>/fx landmine</color> Land mine explosion." +
                "\n<color=#9999ff>/fx fall</color> Breaking your knees." +
                "\n<color=#9999ff>/fx howl</color> Wolf howling." +
                "\n<color=#9999ff>/fx lick</color> Gross licking/slurping sound." +
                "\n<color=#9999ff>/fx headshot</color> Headshot sound effect." +
                "\n<color=#9999ff>/fx chatter</color> Scientist radio chatter." +
                "\n<color=#9999ff>/fx fish</color> Fish song." +
                "\n<color=#9999ff>/fx roar</color> Bear roar." +
                "\n<color=#9999ff>/fx zipper</color> Zipper sound." +
                "\n<color=#9999ff>/fx beartrap</color> Bear trap snap." +
                "\n<color=#9999ff>/fx scdeath</color> Scientist death." +
                "\n<color=#9999ff>/fx bullseye</color> Target bullseye hit.",
                ["NoPerm"] = "<color=#ffc34d>SoundFX</color>: You don't have permission to use that.",
                ["Cooldown"] = "<color=#ffc34d>SoundFX</color>: You are still on a {0} second cooldown.",
                ["Invalid"] = "<color=#ffc34d>SoundFX</color> Not a valid FX command."

            }, this, "en");
        }
        #endregion

        private void Unload()
        {
            foreach (var player in BasePlayer.activePlayerList)
            {
                CuiHelper.DestroyUi(player, "SoundFXMenu");
            }
            config = null;
        }
    }
}