using dodohold.core;

namespace molilian.core
{
    public partial class CouponCenterCore
    {
        public const string Version = "0.0.1";
        private const string CacheKey = "cache:coupon_center:activities:v1";
        private const int CacheExpireSeconds = 600;
        private const int EmptyCacheExpireSeconds = 60;

        private static readonly object _lockObj = new();
        private static CouponCenterActivitiesResponseDTO? _cached;
        private static DateTime _cachedExpireAt = DateTime.MinValue;

        public static CouponCenterActivitiesResponseDTO GetActivities(string channel = "", bool force = false)
        {
            var snapshot = GetSnapshot(force);
            var platformId = NormalizePlatformId(channel);
            return BuildResponse(snapshot, platformId);
        }

        public static void Refresh()
        {
            _ = GetSnapshot(true);
        }

        private static CouponCenterActivitiesResponseDTO GetSnapshot(bool force = false)
        {
            if (!force && _cached != null && _cachedExpireAt > DateTime.Now)
            {
                return _cached;
            }

            if (!force)
            {
                try
                {
                    var cached = RedisHelper.Get<CouponCenterActivitiesResponseDTO>(CacheKey);
                    if (cached != null)
                    {
                        SetLocalCache(cached, CacheExpireSeconds);
                        return cached;
                    }
                }
                catch
                {
                }
            }

            lock (_lockObj)
            {
                if (!force && _cached != null && _cachedExpireAt > DateTime.Now)
                {
                    return _cached;
                }

                var snapshot = LoadFromDb();
                var cacheSeconds = HasData(snapshot) ? CacheExpireSeconds : EmptyCacheExpireSeconds;
                SetLocalCache(snapshot, cacheSeconds);

                if (HasData(snapshot))
                {
                    try
                    {
                        RedisHelper.Set(CacheKey, snapshot, CacheExpireSeconds);
                    }
                    catch
                    {
                    }
                }

                return snapshot;
            }
        }

        private static CouponCenterActivitiesResponseDTO LoadFromDb()
        {
            try
            {
                var platformEntities = new DBContext.Table("coupon_center_platforms")
                    .Where("status=@status", new { status = 1 })
                    .Select<CouponCenterPlatformEntityDTO>()?
                    .OrderBy(item => item.sort)
                    .ThenBy(item => item.id)
                    .ToList() ?? [];

                var platformIds = platformEntities
                    .Where(item => !string.IsNullOrWhiteSpace(item.id))
                    .Select(item => item.id)
                    .ToHashSet(StringComparer.OrdinalIgnoreCase);

                var activityEntities = new DBContext.Table("coupon_center_activities")
                    .Where("status=@status", new { status = 1 })
                    .Select<CouponCenterActivityEntityDTO>()?
                    .Where(item => !string.IsNullOrWhiteSpace(item.id) && platformIds.Contains(item.platform_id))
                    .OrderBy(item => item.sort)
                    .ThenBy(item => item.id)
                    .ToList() ?? [];

                var activityIds = activityEntities
                    .Select(item => item.id)
                    .ToHashSet(StringComparer.OrdinalIgnoreCase);

                var couponLookup = (new DBContext.Table("coupon_center_coupons")
                    .Where("status=@status", new { status = 1 })
                    .Select<CouponCenterCouponEntityDTO>()?
                    .Where(item => !string.IsNullOrWhiteSpace(item.activity_id) && activityIds.Contains(item.activity_id))
                    .OrderBy(item => item.sort)
                    .ThenBy(item => item.id)
                    .GroupBy(item => item.activity_id, StringComparer.OrdinalIgnoreCase)
                    .ToDictionary(
                        group => group.Key,
                        group => group.Select(MapCoupon).ToList(),
                        StringComparer.OrdinalIgnoreCase)) ?? new Dictionary<string, List<CouponCenterCouponDTO>>(StringComparer.OrdinalIgnoreCase);

                return new CouponCenterActivitiesResponseDTO
                {
                    version = Version,
                    platforms = platformEntities.Select(MapPlatform).ToList(),
                    activities = activityEntities.Select(item => MapActivity(item, couponLookup)).ToList(),
                    pagination = new CouponCenterPaginationDTO()
                };
            }
            catch (Exception ex)
            {
                _ = new LoggerLibrary("CouponCenterCore", "LoadFromDb")
                    .Info(ex.Message, ex.StackTrace)
                    .SaveAsync();

                return new CouponCenterActivitiesResponseDTO
                {
                    version = Version,
                    pagination = new CouponCenterPaginationDTO()
                };
            }
        }

        private static CouponCenterActivitiesResponseDTO BuildResponse(CouponCenterActivitiesResponseDTO snapshot, string platformId)
        {
            if (snapshot == null)
            {
                return new CouponCenterActivitiesResponseDTO
                {
                    version = Version,
                    pagination = new CouponCenterPaginationDTO()
                };
            }

            if (string.IsNullOrWhiteSpace(platformId))
            {
                return CloneResponse(snapshot);
            }

            var platforms = snapshot.platforms ?? [];
            var activities = snapshot.activities ?? [];

            return new CouponCenterActivitiesResponseDTO
            {
                version = snapshot.version,
                platforms = platforms
                    .Where(item => item.id.Equals(platformId, StringComparison.OrdinalIgnoreCase))
                    .Select(ClonePlatform)
                    .ToList(),
                activities = activities
                    .Where(item => item.platformId.Equals(platformId, StringComparison.OrdinalIgnoreCase))
                    .Select(CloneActivity)
                    .ToList(),
                pagination = new CouponCenterPaginationDTO()
            };
        }

        private static CouponCenterActivitiesResponseDTO CloneResponse(CouponCenterActivitiesResponseDTO source)
        {
            var platforms = source.platforms ?? [];
            var activities = source.activities ?? [];
            var pagination = source.pagination ?? new CouponCenterPaginationDTO();

            return new CouponCenterActivitiesResponseDTO
            {
                version = source.version,
                platforms = platforms.Select(ClonePlatform).ToList(),
                activities = activities.Select(CloneActivity).ToList(),
                pagination = new CouponCenterPaginationDTO
                {
                    hasMore = pagination.hasMore,
                    nextCursor = pagination.nextCursor
                }
            };
        }

        private static CouponCenterPlatformDTO ClonePlatform(CouponCenterPlatformDTO item)
        {
            return new CouponCenterPlatformDTO
            {
                id = item.id,
                name = item.name,
                iconUrl = item.iconUrl
            };
        }

        private static CouponCenterActivityDTO CloneActivity(CouponCenterActivityDTO item)
        {
            var coupons = item.coupons ?? [];
            return new CouponCenterActivityDTO
            {
                id = item.id,
                platformId = item.platformId,
                name = item.name,
                shortDesc = item.shortDesc,
                deeplink = item.deeplink,
                coupons = coupons.Select(CloneCoupon).ToList()
            };
        }

        private static CouponCenterCouponDTO CloneCoupon(CouponCenterCouponDTO item)
        {
            return new CouponCenterCouponDTO
            {
                id = item.id,
                value = item.value,
                expireTime = item.expireTime,
                category = item.category,
                threshold = item.threshold,
                status = item.status
            };
        }

        private static CouponCenterPlatformDTO MapPlatform(CouponCenterPlatformEntityDTO item)
        {
            return new CouponCenterPlatformDTO
            {
                id = item.id,
                name = item.name,
                iconUrl = item.icon_url
            };
        }

        private static CouponCenterActivityDTO MapActivity(CouponCenterActivityEntityDTO item, IReadOnlyDictionary<string, List<CouponCenterCouponDTO>> couponLookup)
        {
            return new CouponCenterActivityDTO
            {
                id = item.id,
                platformId = item.platform_id,
                name = item.name,
                shortDesc = item.short_desc,
                deeplink = string.IsNullOrWhiteSpace(item.deeplink)
                    ? $"magicchain://coupon-center/activity?activityId={item.id}"
                    : item.deeplink,
                coupons = couponLookup.TryGetValue(item.id, out var coupons)
                    ? coupons.Select(CloneCoupon).ToList()
                    : []
            };
        }

        private static CouponCenterCouponDTO MapCoupon(CouponCenterCouponEntityDTO item)
        {
            return new CouponCenterCouponDTO
            {
                id = item.id,
                value = item.value,
                expireTime = item.expire_time,
                category = item.category,
                threshold = item.threshold,
                status = string.IsNullOrWhiteSpace(item.coupon_status) ? "available" : item.coupon_status
            };
        }

        private static bool HasData(CouponCenterActivitiesResponseDTO snapshot)
        {
            if (snapshot == null)
            {
                return false;
            }

            return (snapshot.platforms?.Count ?? 0) > 0 || (snapshot.activities?.Count ?? 0) > 0;
        }

        private static void SetLocalCache(CouponCenterActivitiesResponseDTO snapshot, int cacheSeconds)
        {
            _cached = snapshot;
            _cachedExpireAt = DateTime.Now.AddSeconds(cacheSeconds);
        }

        private static string NormalizePlatformId(string channel)
        {
            channel = channel?.Trim().ToLowerInvariant() ?? string.Empty;
            return channel switch
            {
                "taobao" => "tb",
                "vip" => "vipshop",
                "tbflash" => "tb_flash",
                "taobaoflash" => "tb_flash",
                "淘宝闪购" => "tb_flash",
                _ => channel,
            };
        }
    }
}
