using System.ComponentModel.DataAnnotations;

namespace Domain.Entities.Crypto
{
    public class Coin
    {
        public virtual List<CoinCategoryMap> CoinCategoryMap { get; private set; } = [];

        public virtual List<CoinMarket> CoinMarket { get; private set; } = [];

        [Key]
        public int ID { get; private set; }

        public string Symbol { get; private set; } = default!;

        public string KorName { get; private set; } = default!;

        public string EngName { get; private set; } = default!;

        public string? LogoImage { get; private set; }

        public string? Description { get; private set; }

        public string? ContractAddress { get; private set; }

        public string? WebsiteUrl { get; private set; }

        public string? WhitepaperUrl { get; private set; }

        public string? TwitterUrl { get; private set; }

        public string? TelegramUrl { get; private set; }

        public bool IsActive { get; private set; } = false;

        public bool IsWarning { get; private set; } = false;

        public bool IsNew { get; private set; } = false;

        public bool IsDelisted { get; private set; } = false;

        public bool IsFeatured { get; private set; } = false;

        public short DisplayOrder { get; private set; } = 0;

        public DateTime? UpdatedAt { get; private set; }

        public DateTime CreatedAt { get; private set; } = DateTime.UtcNow;

        private Coin() { }

        private Coin(
            string symbol,
            string korName,
            string engName,
            string? description,
            string? contractAddress,
            string? websiteUrl,
            string? whitepaperUrl,
            string? twitterUrl,
            string? telegramUrl,
            bool isActive,
            bool isWarning,
            bool isNew,
            bool isDelisted
        ) {
            if (string.IsNullOrWhiteSpace(symbol))
            {
                throw new ArgumentException("Symbol is required.", nameof(symbol));
            }

            if (symbol.Length > 30)
            {
                throw new ArgumentOutOfRangeException(nameof(symbol));
            }

            if (string.IsNullOrWhiteSpace(korName))
            {
                throw new ArgumentException("KorName is required.", nameof(korName));
            }

            if (korName.Length > 200)
            {
                throw new ArgumentOutOfRangeException(nameof(korName));
            }

            if (string.IsNullOrWhiteSpace(engName))
            {
                throw new ArgumentException("EngName is required.", nameof(engName));
            }

            if (engName.Length > 200)
            {
                throw new ArgumentOutOfRangeException(nameof(engName));
            }

            Symbol = symbol.ToUpper();
            KorName = korName;
            EngName = engName;
            Description = description;
            ContractAddress = contractAddress;
            WebsiteUrl = websiteUrl;
            WhitepaperUrl = whitepaperUrl;
            TwitterUrl = twitterUrl;
            TelegramUrl = telegramUrl;
            IsActive = isActive;
            IsWarning = isWarning;
            IsNew = isNew;
            IsDelisted = isDelisted;
        }

        public static Coin Create(
            string symbol,
            string korName,
            string engName,
            string? description = null,
            string? contractAddress = null,
            string? websiteUrl = null,
            string? whitepaperUrl = null,
            string? twitterUrl = null,
            string? telegramUrl = null,
            bool isActive = false,
            bool isWarning = false,
            bool isNew = false,
            bool isDelisted = false
        ) => new(symbol, korName, engName, description, contractAddress, websiteUrl, whitepaperUrl, twitterUrl, telegramUrl, isActive, isWarning, isNew, isDelisted);

        public void Update(
            string symbol,
            string korName,
            string engName,
            string? description,
            string? contractAddress,
            string? websiteUrl,
            string? whitepaperUrl,
            string? twitterUrl,
            string? telegramUrl,
            bool isActive,
            bool isWarning,
            bool isNew,
            bool isDelisted
        ) {
            if (string.IsNullOrWhiteSpace(symbol))
            {
                throw new ArgumentException("Symbol is required.", nameof(symbol));
            }

            if (symbol.Length > 30)
            {
                throw new ArgumentOutOfRangeException(nameof(symbol));
            }

            if (string.IsNullOrWhiteSpace(korName))
            {
                throw new ArgumentException("KorName is required.", nameof(korName));
            }

            if (korName.Length > 200)
            {
                throw new ArgumentOutOfRangeException(nameof(korName));
            }

            if (string.IsNullOrWhiteSpace(engName))
            {
                throw new ArgumentException("EngName is required.", nameof(engName));
            }

            if (engName.Length > 200)
            {
                throw new ArgumentOutOfRangeException(nameof(engName));
            }

            Symbol = symbol.ToUpper();
            KorName = korName;
            EngName = engName;
            Description = description;
            ContractAddress = contractAddress;
            WebsiteUrl = websiteUrl;
            WhitepaperUrl = whitepaperUrl;
            TwitterUrl = twitterUrl;
            TelegramUrl = telegramUrl;
            IsActive = isActive;
            IsWarning = isWarning;
            IsNew = isNew;
            IsDelisted = isDelisted;
            UpdatedAt = DateTime.UtcNow;
        }

        public void SetLogoImage(string? logoImage)
        {
            LogoImage = logoImage;
            UpdatedAt = DateTime.UtcNow;
        }

        public void SetCuration(bool isFeatured, short displayOrder)
        {
            IsFeatured = isFeatured;
            DisplayOrder = displayOrder;
            UpdatedAt = DateTime.UtcNow;
        }

        // Upbit 마켓 데이터로 동기화 (신규 생성용)
        public static Coin SyncFromUpbit(string symbol, string korName, string engName, bool isWarning)
        {
            return new(symbol, korName, engName, null, null, null, null, null, null, isActive: true, isWarning, isNew: false, isDelisted: false);
        }

        // 상장폐지 처리
        public void MarkDelisted()
        {
            IsDelisted = true;
            IsActive = false;
            UpdatedAt = DateTime.UtcNow;
        }

        // 동기화 (이름/경고 상태 갱신, 상폐 해제)
        public void SyncUpdate(string korName, string engName, bool isWarning)
        {
            KorName = korName;
            EngName = engName;
            IsWarning = isWarning;
            if (IsDelisted)
            {
                IsDelisted = false;
                IsActive = true;
            }
            UpdatedAt = DateTime.UtcNow;
        }
    }
}