using HSUI.Config;
using HSUI.Config.Attributes;
using HSUI.Enums;
using HSUI.Helpers;
using HSUI.Interface.Bars;
using HSUI.Interface.StatusEffects;
using System;
using System.Numerics;

namespace HSUI.Interface.GeneralElements
{
    public enum NameplatesOcclusionMode
    {
        None = 0,
        Simple = 1,
        Full
    };

    public enum NameplatesOcclusionType
    {
        Walls = 0,
        WallsAndObjects = 1
    };

    [DisableParentSettings("Strata", "Position")]
    [Section("Nameplates")]
    [SubSection("General", 0)]
    public class NameplatesGeneralConfig : MovablePluginConfigObject
    {
        public new static NameplatesGeneralConfig DefaultConfig() => new NameplatesGeneralConfig();

        [Combo("Occlusion Mode", new string[] { "Disabled", "Simple", "Full" }, help = "This controls wheter you'll see nameplates through walls and objects.\n\nDisabled: Nameplates will always be seen for units in range.\nSimple: Uses simple calculations to check if a nameplate is being covered by walls or objects. Use this for better performance.\nFull: Uses more complex calculations to check if a nameplate is being covered by walls or objects. Use this for better results.")]
        [Order(10)]
        public NameplatesOcclusionMode OcclusionMode = NameplatesOcclusionMode.Full;

        [Combo("Occlusion Type", new string[] { "Walls", "Walls and Objects" }, help = "This controls which kind of objects will cover nameplates.\n\n\nWalls: Default setting. Only walls will cover nameplates.\n\nWalls and Objects: Some objects like columns and trees will also cover nameplates.\nThis Occlusion Type can yield some unexpected results like nameplates for NPCs behind counters not being visible.")]
        [Order(11)]
        public NameplatesOcclusionType OcclusionType = NameplatesOcclusionType.Walls;

        [Checkbox("Try to keep nameplates on screen", spacing = true, help = "Disclaimer: HSUI relies heavily on the the game's default nameplates so this setting won't be a huge improvement.\nThis setting tries to prevent nameplates from being cutoff in the border of the screen, but it won't keep showing nameplates that the game wouldn't.")]
        [Order(20)]
        public bool ClampToScreen = true;

        [Checkbox("Always show nameplate for target")]
        [Order(21)]
        public bool AlwaysShowTargetNameplate = true;

        public int RaycastFlag() => OcclusionType == NameplatesOcclusionType.WallsAndObjects ? 0x2000 : 0x4000;
    }

    [DisableParentSettings("HideWhenInactive")]
    [Section("Nameplates")]
    [SubSection("Player", 0)]
    public class PlayerNameplateConfig : NameplateWithPlayerBarConfig
    {
        public PlayerNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplatePlayerBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig, barConfig)
        {
        }

        public new static PlayerNameplateConfig DefaultConfig()
        {
            return NameplatesHelper.GetNameplateWithBarConfig<PlayerNameplateConfig, NameplatePlayerBarConfig>(
                0xFFD0E5E0,
                0xFF30444A,
                HUDConstants.DefaultPlayerNameplateBarSize
            );
        }
    }

    [DisableParentSettings("HideWhenInactive", "TitleLabelConfig", "SwapLabelsWhenNeeded")]
    [Section("Nameplates")]
    [SubSection("Enemies", 0)]
    public class EnemyNameplateConfig : NameplateWithEnemyBarConfig
    {
        public EnemyNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplateEnemyBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig, barConfig)
        {
        }

        public new static EnemyNameplateConfig DefaultConfig()
        {
            EnemyNameplateConfig config = NameplatesHelper.GetNameplateWithBarConfig<EnemyNameplateConfig, NameplateEnemyBarConfig>(
                0xFF993535,
                0xFF000000,
                HUDConstants.DefaultEnemyNameplateBarSize
            );

            config.SwapLabelsWhenNeeded = false;

            config.NameLabelConfig.Position = new Vector2(-8, 0);
            config.NameLabelConfig.Text = "Lv[level] [name]";
            config.NameLabelConfig.FrameAnchor = DrawAnchor.TopRight;
            config.NameLabelConfig.TextAnchor = DrawAnchor.Right;
            config.NameLabelConfig.Color = PluginConfigColor.FromHex(0xFFFFFFFF);

            config.BarConfig.LeftLabelConfig.Enabled = true;
            config.BarConfig.OnlyShowWhenNotFull = false;

            // debuffs
            LabelConfig durationConfig = new LabelConfig(new Vector2(0, -4), "", DrawAnchor.Bottom, DrawAnchor.Center);
            durationConfig.FontID = FontsConfig.DefaultMediumFontKey;

            LabelConfig stacksConfig = new LabelConfig(new Vector2(-3, 4), "", DrawAnchor.TopRight, DrawAnchor.Center);
            durationConfig.FontID = FontsConfig.DefaultMediumFontKey;
            stacksConfig.Color = new(Vector4.UnitW);
            stacksConfig.OutlineColor = new(Vector4.One);

            StatusEffectIconConfig iconConfig = new StatusEffectIconConfig(durationConfig, stacksConfig);
            iconConfig.Size = new Vector2(30, 30);
            iconConfig.DispellableBorderConfig.Enabled = false;

            Vector2 pos = new Vector2(2, -20);
            Vector2 size = new Vector2(230, 70);

            EnemyNameplateStatusEffectsListConfig debuffs = new EnemyNameplateStatusEffectsListConfig(
                DrawAnchor.TopLeft,
                pos,
                size,
                false,
                true,
                false,
                GrowthDirections.Right | GrowthDirections.Up,
                iconConfig
            );
            debuffs.Limit = 7;
            debuffs.ShowPermanentEffects = true;
            debuffs.IconConfig.DispellableBorderConfig.Enabled = false;
            debuffs.IconPadding = new Vector2(1, 6);
            debuffs.ShowOnlyMine = true;
            debuffs.ShowTooltips = false;
            debuffs.DisableInteraction = true;
            config.DebuffsConfig = debuffs;

            // castbar
            Vector2 castbarSize = new Vector2(config.BarConfig.Size.X, 10);

            LabelConfig castNameConfig = new LabelConfig(new Vector2(0, -1), "", DrawAnchor.Center, DrawAnchor.Center);
            castNameConfig.FontID = FontsConfig.DefaultSmallFontKey;

            NumericLabelConfig castTimeConfig = new NumericLabelConfig(new Vector2(-5, 0), "", DrawAnchor.Right, DrawAnchor.Right);
            castTimeConfig.Enabled = false;
            castTimeConfig.FontID = FontsConfig.DefaultSmallFontKey;
            castTimeConfig.NumberFormat = 1;

            NameplateCastbarConfig castbarConfig = new NameplateCastbarConfig(Vector2.Zero, castbarSize, castNameConfig, castTimeConfig);
            castbarConfig.HealthBarAnchor = DrawAnchor.BottomLeft;
            castbarConfig.Anchor = DrawAnchor.TopLeft;
            castbarConfig.ShowIcon = false;
            config.CastbarConfig = castbarConfig;

            return config;
        }
    }

    [DisableParentSettings("HideWhenInactive")]
    [Section("Nameplates")]
    [SubSection("Party Members", 0)]
    public class PartyMembersNameplateConfig : NameplateWithPlayerBarConfig
    {
        public PartyMembersNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplatePlayerBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig, barConfig)
        {
        }

        public new static PartyMembersNameplateConfig DefaultConfig()
        {
            PartyMembersNameplateConfig config = NameplatesHelper.GetNameplateWithBarConfig<PartyMembersNameplateConfig, NameplatePlayerBarConfig>(
                0xFFD0E5E0,
                0xFF000000,
                HUDConstants.DefaultPlayerNameplateBarSize
            );

            config.BarConfig.UseRoleColor = true;
            config.NameLabelConfig.UseRoleColor = true;
            config.TitleLabelConfig.UseRoleColor = true;
            return config;
        }
    }

    [DisableParentSettings("HideWhenInactive")]
    [Section("Nameplates")]
    [SubSection("Alliance Members", 0)]
    public class AllianceMembersNameplateConfig : NameplateWithPlayerBarConfig
    {
        public AllianceMembersNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplatePlayerBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig, barConfig)
        {
        }

        public new static AllianceMembersNameplateConfig DefaultConfig()
        {
            return NameplatesHelper.GetNameplateWithBarConfig<AllianceMembersNameplateConfig, NameplatePlayerBarConfig>(
                0xFF99BE46,
                0xFF3D4C1C,
                HUDConstants.DefaultPlayerNameplateBarSize
            );
        }
    }

    [DisableParentSettings("HideWhenInactive")]
    [Section("Nameplates")]
    [SubSection("Friends", 0)]
    public class FriendPlayerNameplateConfig : NameplateWithPlayerBarConfig
    {
        public FriendPlayerNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplatePlayerBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig, barConfig)
        {
        }

        public new static FriendPlayerNameplateConfig DefaultConfig()
        {
            return NameplatesHelper.GetNameplateWithBarConfig<FriendPlayerNameplateConfig, NameplatePlayerBarConfig>(
                0xFFEB6211,
                0xFF4A2008,
                HUDConstants.DefaultPlayerNameplateBarSize
            );
        }
    }

    [DisableParentSettings("HideWhenInactive")]
    [Section("Nameplates")]
    [SubSection("Other Players", 0)]
    public class OtherPlayerNameplateConfig : NameplateWithPlayerBarConfig
    {
        public OtherPlayerNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplatePlayerBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig, barConfig)
        {
        }

        public new static OtherPlayerNameplateConfig DefaultConfig()
        {
            return NameplatesHelper.GetNameplateWithBarConfig<OtherPlayerNameplateConfig, NameplatePlayerBarConfig>(
                0xFF91BBD8,
                0xFF33434E,
                HUDConstants.DefaultPlayerNameplateBarSize
            );
        }
    }

    [DisableParentSettings("HideWhenInactive")]
    [Section("Nameplates")]
    [SubSection("Pets", 0)]
    public class PetNameplateConfig : NameplateWithNPCBarConfig
    {
        public PetNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplateBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig, barConfig)
        {
        }

        public new static PetNameplateConfig DefaultConfig()
        {
            PetNameplateConfig config = NameplatesHelper.GetNameplateWithBarConfig<PetNameplateConfig, NameplateBarConfig>(
                0xFFD1E5C8,
                0xFF2A2F28,
                HUDConstants.DefaultPlayerNameplateBarSize
            );
            config.OnlyShowWhenTargeted = true;
            config.SwapLabelsWhenNeeded = false;
            config.NameLabelConfig.Text = "Lv[level] [name]";
            config.NameLabelConfig.FontID = FontsConfig.DefaultSmallFontKey;
            config.TitleLabelConfig.FontID = FontsConfig.DefaultSmallFontKey;

            return config;
        }
    }

    [DisableParentSettings("HideWhenInactive")]
    [Section("Nameplates")]
    [SubSection("NPCs", 0)]
    public class NPCNameplateConfig : NameplateWithNPCBarConfig
    {
        public NPCNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplateBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig, barConfig)
        {
        }

        public new static NPCNameplateConfig DefaultConfig()
        {
            NPCNameplateConfig config = NameplatesHelper.GetNameplateWithBarConfig<NPCNameplateConfig, NameplateBarConfig>(
                0xFFD1E5C8,
                0xFF3A4b1E,
                HUDConstants.DefaultPlayerNameplateBarSize
            );
            config.NameLabelConfig.Position = new Vector2(0, -20);
            config.TitleLabelConfig.Position = Vector2.Zero;

            return config;
        }
    }

    [DisableParentSettings("HideWhenInactive", "SwapLabelsWhenNeeded")]
    [Section("Nameplates")]
    [SubSection("Minions", 0)]
    public class MinionNPCNameplateConfig : NameplateConfig
    {
        public MinionNPCNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig)
            : base(position, nameLabel, titleLabelConfig)
        {
        }

        public new static MinionNPCNameplateConfig DefaultConfig()
        {
            MinionNPCNameplateConfig config = NameplatesHelper.GetNameplateConfig<MinionNPCNameplateConfig>(0xFFFFFFFF, 0xFF000000);
            config.OnlyShowWhenTargeted = true;
            config.SwapLabelsWhenNeeded = false;
            config.NameLabelConfig.Position = new Vector2(0, -17);
            config.NameLabelConfig.FontID = FontsConfig.DefaultSmallFontKey;
            config.TitleLabelConfig.Position = new Vector2(0, 0);
            config.TitleLabelConfig.FontID = FontsConfig.DefaultSmallFontKey;

            return config;
        }
    }

    [DisableParentSettings("HideWhenInactive", "SwapLabelsWhenNeeded")]
    [Section("Nameplates")]
    [SubSection("Objects", 0)]
    public class ObjectsNameplateConfig : NameplateConfig
    {
        public ObjectsNameplateConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig)
            : base(position, nameLabel, titleLabelConfig)
        {
        }

        public new static ObjectsNameplateConfig DefaultConfig()
        {
            ObjectsNameplateConfig config = NameplatesHelper.GetNameplateConfig<ObjectsNameplateConfig>(0xFFFFFFFF, 0xFF000000);
            config.SwapLabelsWhenNeeded = false;

            return config;
        }
    }

    public class NameplateConfig : MovablePluginConfigObject
    {
        [Checkbox("Only show when targeted")]
        [Order(1)]
        public bool OnlyShowWhenTargeted = false;

        [Checkbox("Swap Name and Title labels when needed", spacing = true, help = "This will swap the contents of these labels depending on if the title goes before or after the name of a player.")]
        [Order(20)]
        public bool SwapLabelsWhenNeeded = true;

        [NestedConfig("Name Label", 21)]
        public EditableLabelConfig NameLabelConfig = null!;

        [NestedConfig("Title Label", 22)]
        public EditableNonFormattableLabelConfig TitleLabelConfig = null!;

        [NestedConfig("Change Alpha Based on Range", 145)]
        public NameplateRangeConfig RangeConfig = new();

        [NestedConfig("Visibility", 200)]
        public VisibilityConfig VisibilityConfig = new VisibilityConfig();

        public NameplateConfig(Vector2 position, EditableLabelConfig nameLabelConfig, EditableNonFormattableLabelConfig titleLabelConfig)
            : base()
        {
            Position = position;
            NameLabelConfig = nameLabelConfig;
            TitleLabelConfig = titleLabelConfig;
        }

        public NameplateConfig() : base() { } // don't remove
    }

    public interface NameplateWithBarConfig
    {
        public NameplateBarConfig GetBarConfig();
    }

    public class NameplateWithNPCBarConfig : NameplateConfig, NameplateWithBarConfig
    {
        [NestedConfig("Health Bar", 40)]
        public NameplateBarConfig BarConfig = null!;

        /// <summary>Quest/state icon (e.g. ! ? above NPCs). Use Position and Size to resize and reposition around the nameplate.</summary>
        [NestedConfig("Icon (Quest/State)", 42)]
        public NameplateIconConfig IconConfig = new NameplateIconConfig(
            new Vector2(0, -28),
            new Vector2(32, 32),
            DrawAnchor.Bottom,
            DrawAnchor.Top
        )
        { Strata = StrataLevel.LOWEST };

        public NameplateBarConfig GetBarConfig() => BarConfig;

        public NameplateWithNPCBarConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplateBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig)
        {
            BarConfig = barConfig;
        }

        public NameplateWithNPCBarConfig() : base() { } // don't remove
    }

    public class NameplateWithPlayerBarConfig : NameplateConfig, NameplateWithBarConfig
    {
        [NestedConfig("Health Bar", 40)]
        public NameplatePlayerBarConfig BarConfig = null!;

        [NestedConfig("Role/Job Icon", 50)]
        public NameplateRoleJobIconConfig RoleIconConfig = new NameplateRoleJobIconConfig(
            new Vector2(-5, 0),
            new Vector2(30, 30),
            DrawAnchor.Right,
            DrawAnchor.Left
        )
        { Strata = StrataLevel.LOWEST };

        [NestedConfig("Player State Icon", 55)]
        public NameplatePlayerIconConfig StateIconConfig = new NameplatePlayerIconConfig(
            new Vector2(5, 0),
            new Vector2(30, 30),
            DrawAnchor.Left,
            DrawAnchor.Right
        )
        { Strata = StrataLevel.LOWEST };

        public NameplateBarConfig GetBarConfig() => BarConfig;

        public NameplateWithPlayerBarConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplatePlayerBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig)
        {
            BarConfig = barConfig;
        }

        public NameplateWithPlayerBarConfig() : base() { } // don't remove
    }

    public class NameplateWithEnemyBarConfig : NameplateConfig, NameplateWithBarConfig
    {
        [NestedConfig("Health Bar", 40)]
        public NameplateEnemyBarConfig BarConfig = null!;

        [NestedConfig("Icon", 45)]
        public NameplateIconConfig IconConfig = new NameplateIconConfig(
            new Vector2(0, 0),
            new Vector2(40, 40),
            DrawAnchor.Right,
            DrawAnchor.Left
        )
        { PrioritizeHealthBarAnchor = true, Strata = StrataLevel.LOWEST };

        [NestedConfig("Company Icon (PvP)", 46, collapsingHeader = false)]
        public NameplateCompanyIconConfig CompanyIconConfig = new NameplateCompanyIconConfig(
            new Vector2(-5, 0),
            new Vector2(24, 24),
            DrawAnchor.Right,
            DrawAnchor.Left
        )
        { PrioritizeHealthBarAnchor = true, Strata = StrataLevel.LOWEST };

        [NestedConfig("Role/Job Icon (enemy players)", 47)]
        public NameplateRoleJobIconConfig RoleIconConfig = new NameplateRoleJobIconConfig(
            new Vector2(-35, 0),
            new Vector2(24, 24),
            DrawAnchor.Right,
            DrawAnchor.Left
        )
        { PrioritizeHealthBarAnchor = true, Strata = StrataLevel.LOWEST };

        [NestedConfig("Debuffs", 50)]
        public EnemyNameplateStatusEffectsListConfig DebuffsConfig = null!;

        [NestedConfig("Castbar", 55)]
        public NameplateCastbarConfig CastbarConfig = null!;

        public NameplateBarConfig GetBarConfig() => BarConfig;

        public NameplateWithEnemyBarConfig(
            Vector2 position,
            EditableLabelConfig nameLabel,
            EditableNonFormattableLabelConfig titleLabelConfig,
            NameplateEnemyBarConfig barConfig)
            : base(position, nameLabel, titleLabelConfig)
        {
            BarConfig = barConfig;
        }

        public NameplateWithEnemyBarConfig() : base() { } // don't remove
    }

    [DisableParentSettings("HideWhenInactive")]
    public class NameplateBarConfig : BarConfig
    {
        [Checkbox("Only Show when not at full Health")]
        [Order(1)]
        public bool OnlyShowWhenNotFull = true;

        [Checkbox("Hide Health when fully depleted", help = "This will hide the healthbar when the characters HP has been brought to zero")]
        [Order(2)]
        public bool HideHealthAtZero = true;

        [Checkbox("Disable Interaction")]
        [Order(3)]
        public bool DisableInteraction = false;

        [Checkbox("Use Different Size when targeted", spacing = true)]
        [Order(31)]
        public bool UseDifferentSizeWhenTargeted = false;

        [DragInt2("Size When Targeted", min = 1, max = 4000)]
        [Order(32, collapseWith = nameof(UseDifferentSizeWhenTargeted))]
        public Vector2 SizeWhenTargeted;

        [ColorEdit4("Targeted Border Color")]
        [Order(38, collapseWith = nameof(DrawBorder))]
        public PluginConfigColor TargetedBorderColor = PluginConfigColor.FromHex(0xFFFFFFFF);

        [DragInt("Targeted Border Thickness", min = 1, max = 10)]
        [Order(39, collapseWith = nameof(DrawBorder))]
        public int TargetedBorderThickness = 2;

        [NestedConfig("Color Based On Health Value", 50, collapsingHeader = false)]
        public ColorByHealthValueConfig ColorByHealth = new ColorByHealthValueConfig();

        [Checkbox("Hide Health if Possible", spacing = true, help = "This will hide any label that has a health tag if the character doesn't have health (ie minions, friendly npcs, etc)")]
        [Order(121)]
        public bool HideHealthIfPossible = true;

        [NestedConfig("Left Text", 125)]
        public EditableLabelConfig LeftLabelConfig = null!;

        [NestedConfig("Right Text", 130)]
        public EditableLabelConfig RightLabelConfig = null!;

        [NestedConfig("Optional Text", 131)]
        public EditableLabelConfig OptionalLabelConfig = null!;

        [NestedConfig("Shields", 140)]
        public ShieldConfig ShieldConfig = new ShieldConfig();

        [NestedConfig("Custom Mouseover Area", 150)]
        public MouseoverAreaConfig MouseoverAreaConfig = new MouseoverAreaConfig();

        public NameplateBarConfig(Vector2 position, Vector2 size, EditableLabelConfig leftLabelConfig, EditableLabelConfig rightLabelConfig, EditableLabelConfig optionalLabelConfig)
            : base(position, size, new PluginConfigColor(new(40f / 255f, 40f / 255f, 40f / 255f, 100f / 100f)))
        {
            Position = position;
            Size = size;
            LeftLabelConfig = leftLabelConfig;
            RightLabelConfig = rightLabelConfig;
            OptionalLabelConfig = optionalLabelConfig;
            BackgroundColor = new PluginConfigColor(new(0f / 255f, 0f / 255f, 0f / 255f, 100f / 100f));
            ColorByHealth.Enabled = false;
            MouseoverAreaConfig.Enabled = false;
        }

        public bool IsVisible(uint hp, uint maxHp)
        {
            return Enabled && (!OnlyShowWhenNotFull || hp < maxHp) && !(HideHealthAtZero && hp <= 0);
        }

        public Vector2 GetSize(bool targeted)
        {
            return targeted && UseDifferentSizeWhenTargeted ? SizeWhenTargeted : Size;
        }

        public NameplateBarConfig() : base(Vector2.Zero, Vector2.Zero, PluginConfigColor.Empty) { } // don't remove
    }

    public class NameplatePlayerBarConfig : NameplateBarConfig
    {
        [Checkbox("Use Job Color", spacing = true)]
        [Order(45)]
        public bool UseJobColor = false;

        [Checkbox("Use Role Color")]
        [Order(46)]
        public bool UseRoleColor = false;

        [Checkbox("Job Color As Background Color", spacing = true)]
        [Order(50)]
        public bool UseJobColorAsBackgroundColor = false;

        [Checkbox("Role Color As Background Color")]
        [Order(51)]
        public bool UseRoleColorAsBackgroundColor = false;

        public NameplatePlayerBarConfig(Vector2 position, Vector2 size, EditableLabelConfig leftLabelConfig, EditableLabelConfig rightLabelConfig, EditableLabelConfig optionalLabelConfig)
            : base(position, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig)
        {
        }
    }

    public class NameplateEnemyBarConfig : NameplateBarConfig
    {
        [Checkbox("Use State Colors", spacing = true)]
        [Order(45)]
        public bool UseStateColor = true;

        [ColorEdit4("Unengaged")]
        [Order(46, collapseWith = nameof(UseStateColor))]
        public PluginConfigColor UnengagedColor = PluginConfigColor.FromHex(0xFFDA9D2E);

        [ColorEdit4("Unengaged (Hostile)")]
        [Order(47, collapseWith = nameof(UseStateColor))]
        public PluginConfigColor UnengagedHostileColor = PluginConfigColor.FromHex(0xFF994B35);

        [ColorEdit4("Engaged")]
        [Order(48, collapseWith = nameof(UseStateColor))]
        public PluginConfigColor EngagedColor = PluginConfigColor.FromHex(0xFF993535);

        [ColorEdit4("Claimed")]
        [Order(49, collapseWith = nameof(UseStateColor))]
        public PluginConfigColor ClaimedColor = PluginConfigColor.FromHex(0xFFEA93EA);

        [ColorEdit4("Unclaimed")]
        [Order(50, collapseWith = nameof(UseStateColor))]
        public PluginConfigColor UnclaimedColor = PluginConfigColor.FromHex(0xFFE5BB9E);

        [Checkbox("Use Custom Color when being targeted", spacing = true, help = "This will change the color of the bar when the enemy is targeting the player.")]
        [Order(51)]
        public bool UseCustomColorWhenBeingTargeted = false;

        [ColorEdit4("Targeted")]
        [Order(52, collapseWith = nameof(UseCustomColorWhenBeingTargeted))]
        public PluginConfigColor CustomColorWhenBeingTargeted = PluginConfigColor.FromHex(0xFFC4216D);

        [NestedConfig("Order Label", 132)]
        public DefaultFontLabelConfig OrderLabelConfig = new DefaultFontLabelConfig(new Vector2(5, 0), "", DrawAnchor.Right, DrawAnchor.Left)
        {
            Strata = StrataLevel.LOWEST
        };

        public NameplateEnemyBarConfig(Vector2 position, Vector2 size, EditableLabelConfig leftLabelConfig, EditableLabelConfig rightLabelConfig, EditableLabelConfig optionalLabelConfig)
            : base(position, size, leftLabelConfig, rightLabelConfig, optionalLabelConfig)
        {

        }
    }

    [Exportable(false)]
    public class NameplateRangeConfig : PluginConfigObject
    {
        [DragInt("Fade start range (yalms)", min = 1, max = 500)]
        [Order(5)]
        public int StartRange = 50;

        [DragInt("Fade end range (yalms)", min = 1, max = 500)]
        [Order(10)]
        public int EndRange = 64;

        public float AlphaForDistance(float distance, float maxAlpha = 1f)
        {
            float diff = distance - StartRange;
            if (!Enabled || diff <= 0)
            {
                return maxAlpha;
            }

            float a = diff / (EndRange - StartRange);
            return Math.Max(0, Math.Min(maxAlpha, 1 - a));
        }
    }

    public class EnemyNameplateStatusEffectsListConfig : StatusEffectsListConfig
    {
        [Anchor("Health Bar Anchor")]
        [Order(4)]
        public DrawAnchor HealthBarAnchor = DrawAnchor.BottomLeft;

        public EnemyNameplateStatusEffectsListConfig(DrawAnchor anchor, Vector2 position, Vector2 size, bool showBuffs, bool showDebuffs, bool showPermanentEffects,
            GrowthDirections growthDirections, StatusEffectIconConfig iconConfig)
            : base(position, size, showBuffs, showDebuffs, showPermanentEffects, growthDirections, iconConfig)
        {
            HealthBarAnchor = anchor;
        }
    }

    [DisableParentSettings("AnchorToUnitFrame", "UnitFrameAnchor", "HideWhenInactive", "FillDirection")]
    public class NameplateCastbarConfig : TargetCastbarConfig
    {
        [Checkbox("Match Width with Health Bar")]
        [Order(11)]
        public bool MatchWidth = false;

        [Checkbox("Match Height with Health Bar")]
        [Order(12)]
        public bool MatchHeight = false;

        [Anchor("Health Bar Anchor")]
        [Order(16)]
        public DrawAnchor HealthBarAnchor = DrawAnchor.BottomLeft;

        public NameplateCastbarConfig(Vector2 position, Vector2 size, LabelConfig castNameConfig, NumericLabelConfig castTimeConfig)
            : base(position, size, castNameConfig, castTimeConfig)
        {

        }
    }

    internal static class NameplatesHelper
    {
        internal static T GetNameplateConfig<T>(uint bgColor, uint borderColor) where T : NameplateConfig
        {
            EditableLabelConfig nameLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "[name]", DrawAnchor.Top, DrawAnchor.Bottom)
            {
                Color = PluginConfigColor.FromHex(bgColor),
                OutlineColor = PluginConfigColor.FromHex(borderColor),
                FontID = FontsConfig.DefaultMediumFontKey
            };

            EditableNonFormattableLabelConfig titleLabelConfig = new EditableNonFormattableLabelConfig(new Vector2(0, -25), "<[title]>", DrawAnchor.Top, DrawAnchor.Bottom)
            {
                Color = PluginConfigColor.FromHex(bgColor),
                OutlineColor = PluginConfigColor.FromHex(borderColor),
                FontID = FontsConfig.DefaultMediumFontKey
            };

            return (T)Activator.CreateInstance(typeof(T), Vector2.Zero, nameLabelConfig, titleLabelConfig)!;
        }

        internal static T GetNameplateWithBarConfig<T, B>(uint bgColor, uint borderColor, Vector2 barSize)
            where T : NameplateConfig
            where B : NameplateBarConfig
        {
            EditableLabelConfig leftLabelConfig = new EditableLabelConfig(new Vector2(5, 0), "[health:current-short]", DrawAnchor.Left, DrawAnchor.Left)
            {
                Enabled = false,
                FontID = FontsConfig.DefaultMediumFontKey,
                Strata = StrataLevel.LOWEST
            };
            EditableLabelConfig rightLabelConfig = new EditableLabelConfig(new Vector2(-5, 0), "", DrawAnchor.Right, DrawAnchor.Right)
            {
                Enabled = false,
                FontID = FontsConfig.DefaultMediumFontKey,
                Strata = StrataLevel.LOWEST
            };
            EditableLabelConfig optionalLabelConfig = new EditableLabelConfig(new Vector2(0, 0), "", DrawAnchor.Center, DrawAnchor.Center)
            {
                Enabled = false,
                FontID = FontsConfig.DefaultSmallFontKey,
                Strata = StrataLevel.LOWEST
            };

            var barConfig = Activator.CreateInstance(typeof(B), new Vector2(0, -5), barSize, leftLabelConfig, rightLabelConfig, optionalLabelConfig)!;
            if (barConfig is BarConfig bar)
            {
                bar.FillColor = PluginConfigColor.FromHex(bgColor);
                bar.BackgroundColor = PluginConfigColor.FromHex(0xAA000000);
            }

            if (barConfig is NameplateBarConfig nameplateBar)
            {
                nameplateBar.SizeWhenTargeted = nameplateBar.Size;
            }

            EditableLabelConfig nameLabelConfig = new EditableLabelConfig(new Vector2(0, -20), "[name]", DrawAnchor.Top, DrawAnchor.Bottom)
            {
                Color = PluginConfigColor.FromHex(bgColor),
                OutlineColor = PluginConfigColor.FromHex(borderColor),
                FontID = FontsConfig.DefaultMediumFontKey,
                Strata = StrataLevel.LOWEST
            };
            EditableNonFormattableLabelConfig titleLabelConfig = new EditableNonFormattableLabelConfig(new Vector2(0, 0), "<[title]>", DrawAnchor.Top, DrawAnchor.Bottom)
            {
                Color = PluginConfigColor.FromHex(bgColor),
                OutlineColor = PluginConfigColor.FromHex(borderColor),
                FontID = FontsConfig.DefaultMediumFontKey,
                Strata = StrataLevel.LOWEST
            };

            return (T)Activator.CreateInstance(typeof(T), Vector2.Zero, nameLabelConfig, titleLabelConfig, barConfig)!;
        }
    }
}
