// Copyright (c) 2026 EzAdmin. All rights reserved.
// Licensed under the EzAdmin Client License. See LICENSE-CLIENT.txt.

using System;
using System.Collections.Generic;
using UnityEngine;

namespace EzAdmin.Client
{

    [AttributeUsage(AttributeTargets.Field)]
    public sealed class EzAdminGroupAttribute : Attribute
    {
        public readonly string Title;
        public EzAdminGroupAttribute(string title) { Title = title; }
    }

    public static class EzAdminBrand
    {
        public static readonly Color Green = new Color32(0x22, 0xC5, 0x5E, 0xFF);
        public static readonly Color GreenSoft = new Color32(0x4A, 0xDE, 0x80, 0xFF);
        public static readonly Color GreenDeep = new Color32(0x12, 0xA1, 0x50, 0xFF);
        public static readonly Color Ink = new Color32(0x14, 0x14, 0x14, 0xFF);
        public static readonly Color Panel = new Color32(0x12, 0x15, 0x1C, 0xFF);
        public static readonly Color Discord = new Color32(0x58, 0x65, 0xF2, 0xFF);

        private static readonly Vector2[] E = Poly(236, 282, 572, 282, 572, 386, 352, 386, 352, 484, 636, 484,
                                                   636, 588, 352, 588, 352, 774, 576, 774, 576, 878, 236, 878);
        private static readonly Vector2[] AOuter = Poly(742, 282, 814, 282, 1068, 778, 944, 778, 886, 660,
                                                        670, 660, 612, 778, 488, 778);
        private static readonly Vector2[] AHole = Poly(778, 424, 704, 576, 852, 576);
        private const float Radius = 232f;

        private static readonly Dictionary<int, Texture2D> Textures = new Dictionary<int, Texture2D>();
        private static readonly Dictionary<int, Sprite> Sprites = new Dictionary<int, Sprite>();

        public static Texture2D Logo(int size = 128)
        {
            size = Mathf.Clamp(size, 16, 512);
            Texture2D cached;
            if (Textures.TryGetValue(size, out cached) && cached != null) return cached;

            var texture = new Texture2D(size, size, TextureFormat.RGBA32, false)
            {
                name = "EzAdmin logo",
                wrapMode = TextureWrapMode.Clamp,
                filterMode = FilterMode.Bilinear,
                hideFlags = HideFlags.HideAndDontSave
            };
            var pixels = new Color[size * size];
            const int samples = 4;
            float scale = 1024f / size;
            for (int py = 0; py < size; py++)
            {
                for (int px = 0; px < size; px++)
                {
                    float r = 0, g = 0, b = 0, a = 0;
                    for (int sy = 0; sy < samples; sy++)
                    {
                        for (int sx = 0; sx < samples; sx++)
                        {
                            float x = (px + (sx + 0.5f) / samples) * scale;

                            float y = (size - py - (sy + 0.5f) / samples) * scale;
                            Color c = Sample(x, y);
                            r += c.r * c.a; g += c.g * c.a; b += c.b * c.a; a += c.a;
                        }
                    }
                    float n = samples * samples;
                    pixels[py * size + px] = a > 0 ? new Color(r / a, g / a, b / a, a / n) : Color.clear;
                }
            }
            texture.SetPixels(pixels);
            texture.Apply();
            Textures[size] = texture;
            return texture;
        }

        public static Sprite LogoSprite(int size = 64)
        {
            Sprite cached;
            if (Sprites.TryGetValue(size, out cached) && cached != null) return cached;
            var texture = Logo(size);
            var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), 100f);
            sprite.name = "EzAdmin logo";
            Sprites[size] = sprite;
            return sprite;
        }

        private static Color Sample(float x, float y)
        {
            if (!InTile(x, y)) return Color.clear;
            if (Inside(AOuter, x, y) && !Inside(AHole, x, y))
            {
                float t = Mathf.InverseLerp(282f, 778f, y);
                return Color.Lerp(GreenSoft, GreenDeep, t);
            }
            if (Inside(E, x, y)) return Color.white;
            return Ink;
        }

        private static bool InTile(float x, float y)
        {
            float cx = Mathf.Clamp(x, Radius, 1024f - Radius);
            float cy = Mathf.Clamp(y, Radius, 1024f - Radius);
            float dx = x - cx, dy = y - cy;
            return x >= 0 && y >= 0 && x <= 1024f && y <= 1024f && dx * dx + dy * dy <= Radius * Radius;
        }

        private static bool Inside(Vector2[] poly, float x, float y)
        {
            bool inside = false;
            for (int i = 0, j = poly.Length - 1; i < poly.Length; j = i++)
            {
                if ((poly[i].y > y) != (poly[j].y > y) &&
                    x < (poly[j].x - poly[i].x) * (y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x)
                {
                    inside = !inside;
                }
            }
            return inside;
        }

        private static Vector2[] Poly(params float[] xy)
        {
            var points = new Vector2[xy.Length / 2];
            for (int i = 0; i < points.Length; i++) points[i] = new Vector2(xy[i * 2], xy[i * 2 + 1]);
            return points;
        }
    }
}
