using SimpleCore.PropType;
using System;
using System.Collections.Generic;
using System.Globalization;

namespace StandardScene.Magnetic.Tasking
{
    internal static class Fass2SiteFieldReader
    {
        public static Fass2SiteActionData Read(Site site)
        {
            var data = new Fass2SiteActionData();
            if (site?.fields == null)
            {
                return data;
            }

            data.StartStop = TryReadByte(site.fields, Fass2SiteFields.StartStop);
            data.Byroad = TryReadByte(site.fields, Fass2SiteFields.Byroad);
            data.Direction = TryReadByte(site.fields, Fass2SiteFields.Direction);
            data.Orientation = TryReadByte(site.fields, Fass2SiteFields.Orientation);
            data.Lift = TryReadByte(site.fields, Fass2SiteFields.Lift);
            data.Roll = TryReadByte(site.fields, Fass2SiteFields.Roll);
            data.Charge = TryReadByte(site.fields, Fass2SiteFields.Charge);
            data.Obstacle = TryReadByte(site.fields, Fass2SiteFields.Obstacle);
            data.Audio = TryReadByte(site.fields, Fass2SiteFields.Audio);
            data.Light = TryReadByte(site.fields, Fass2SiteFields.Light);
            data.Rest = TryReadByte(site.fields, Fass2SiteFields.Rest);
            data.Clamp = TryReadByte(site.fields, Fass2SiteFields.Clamp);
            data.Tray = TryReadByte(site.fields, Fass2SiteFields.Tray);
            data.Shutdown = TryReadByte(site.fields, Fass2SiteFields.Shutdown);
            data.PrecisionStop = TryReadBool(site.fields, Fass2SiteFields.PrecisionStop);
            data.WaitMode = TryReadString(site.fields, Fass2SiteFields.WaitMode);
            data.ControlArea = TryReadString(site.fields, Fass2SiteFields.ControlArea);
            data.ControlCapacity = TryReadInt(site.fields, Fass2SiteFields.ControlCapacity);
            data.ControlReleaseStartStop = TryReadByte(site.fields, Fass2SiteFields.ControlReleaseStartStop);

            if (!data.ControlCapacity.HasValue)
            {
                TryFillRegionCapacityFallback(site.fields, data);
            }

            return data;
        }

        public static string BuildFieldsSignature(IReadOnlyList<int> siteIds, int fromIndex, Func<int, Site> getSite)
        {
            if (siteIds == null || siteIds.Count == 0)
            {
                return string.Empty;
            }

            var parts = new List<string>(siteIds.Count - fromIndex);
            for (var i = Math.Max(0, fromIndex); i < siteIds.Count; i++)
            {
                var site = getSite(siteIds[i]);
                if (site?.fields == null)
                {
                    parts.Add($"{siteIds[i]}:");
                    continue;
                }

                var keys = new List<string>();
                foreach (var pair in site.fields)
                {
                    if (pair.Key.StartsWith("Fass2_", StringComparison.OrdinalIgnoreCase) ||
                        pair.Key.Equals(Fass2SiteFields.TagValue, StringComparison.OrdinalIgnoreCase))
                    {
                        keys.Add($"{pair.Key}={pair.Value}");
                    }
                }

                keys.Sort(StringComparer.OrdinalIgnoreCase);
                parts.Add($"{siteIds[i]}:{string.Join("|", keys)}");
            }

            return string.Join(";", parts);
        }

        private static byte? TryReadByte(Dictionary<string, string> fields, string key)
        {
            if (!fields.TryGetValue(key, out var text) || string.IsNullOrWhiteSpace(text))
            {
                return null;
            }

            if (byte.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
            {
                return value;
            }

            return null;
        }

        private static bool TryReadBool(Dictionary<string, string> fields, string key)
        {
            if (!fields.TryGetValue(key, out var text) || string.IsNullOrWhiteSpace(text))
            {
                return false;
            }

            return bool.TryParse(text, out var value) && value
                   || text == "1"
                   || string.Equals(text, "true", StringComparison.OrdinalIgnoreCase);
        }

        private static string TryReadString(Dictionary<string, string> fields, string key)
        {
            return fields.TryGetValue(key, out var text) ? text : null;
        }

        private static int? TryReadInt(Dictionary<string, string> fields, string key)
        {
            if (!fields.TryGetValue(key, out var text) || string.IsNullOrWhiteSpace(text))
            {
                return null;
            }

            if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
            {
                return value;
            }

            return null;
        }

        private static void TryFillRegionCapacityFallback(Dictionary<string, string> fields, Fass2SiteActionData data)
        {
            foreach (var pair in fields)
            {
                if (string.IsNullOrEmpty(pair.Key) ||
                    !pair.Key.StartsWith("Region", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                if (int.TryParse(pair.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var maxCount) &&
                    maxCount > 0)
                {
                    data.ControlCapacity = maxCount;
                }

                return;
            }
        }
    }
}
