using AudioWallpaper.ActivityWatch;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace AudioWallpaper.ActivityWatch {
    internal class ActivityAnalyzer {
        private readonly ActivityAnalyzerConfig _config;
        private readonly TimeZoneInfo _timeZone;

        public ActivityAnalyzer(ActivityAnalyzerConfig config = null) {
            _config = config ?? new ActivityAnalyzerConfig();

            // 初始化时区
            try {
                _timeZone = TimeZoneInfo.FindSystemTimeZoneById(GetWindowsTimeZoneId(_config.Timezone));
            } catch (TimeZoneNotFoundException) {
                Console.WriteLine($"警告：未知时区 '{_config.Timezone}'，使用默认时区 'China Standard Time'");
                _timeZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
            }
        }

        private string GetWindowsTimeZoneId(string timezone) {
            // 映射一些常见的时区名称到Windows时区ID
            var timeZoneMap = new Dictionary<string, string>
            {
                { "Asia/Shanghai", "China Standard Time" },
                { "UTC", "UTC" },
                { "US/Eastern", "Eastern Standard Time" },
                { "US/Pacific", "Pacific Standard Time" },
                { "Europe/London", "GMT Standard Time" },
                { "Europe/Paris", "W. Europe Standard Time" }
            };

            return timeZoneMap.ContainsKey(timezone) ? timeZoneMap[timezone] : timezone;
        }

        private DateTime? ParseTimestamp(string timestampStr) {
            if (string.IsNullOrEmpty(timestampStr))
                return null;

            try {
                // 方法1：直接解析ISO格式
                if (DateTime.TryParse(timestampStr, out DateTime dt)) {
                    // 转换到指定时区
                    if (dt.Kind == DateTimeKind.Utc) {
                        return TimeZoneInfo.ConvertTimeFromUtc(dt, _timeZone);
                    } else if (dt.Kind == DateTimeKind.Unspecified) {
                        return TimeZoneInfo.ConvertTime(dt, _timeZone);
                    }
                    return dt;
                }

                // 方法2：手动解析
                string cleanTimestamp = timestampStr.Replace('T', ' ');

                if (cleanTimestamp.Contains('+'))
                    cleanTimestamp = cleanTimestamp.Split('+')[0];
                else if (cleanTimestamp.Contains('Z'))
                    cleanTimestamp = cleanTimestamp.Replace("Z", "");

                // 移除毫秒部分
                cleanTimestamp = Regex.Replace(cleanTimestamp, @"\.\d+", "");

                if (DateTime.TryParseExact(cleanTimestamp, "yyyy-MM-dd HH:mm:ss",
                    CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsedDt)) {
                    return TimeZoneInfo.ConvertTime(parsedDt, _timeZone);
                }

                return null;
            } catch (Exception ex) {
                Console.WriteLine($"警告：无法解析时间戳 '{timestampStr}': {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 解析从ActivityWatchClient获取的原始活动数据
        /// </summary>
        /// <param name="rawData">ActivityWatchClient.GetEventsAsync()返回的数据</param>
        /// <returns>解析后的活动条目列表</returns>
        public List<ActivityEntry> ParseActivityData(List<Dictionary<string, object>> rawData) {
            var activities = new List<ActivityEntry>();

            if (rawData == null || !rawData.Any())
                return activities;

            foreach (var entry in rawData) {
                var processed = ProcessDictionaryEntry(entry);
                if (processed != null)
                    activities.AddRange(processed);
            }

            return activities.OrderBy(a => a.Timestamp).ToList();
        }

        /// <summary>
        /// 从JSON字符串解析活动数据（兼容原有功能）
        /// </summary>
        /// <param name="jsonString">JSON格式的活动数据</param>
        /// <returns>解析后的活动条目列表</returns>
        public List<ActivityEntry> ParseActivityDataFromJson(string jsonString) {
            var activities = new List<ActivityEntry>();

            if (string.IsNullOrEmpty(jsonString))
                return activities;

            try {
                // 尝试解析为JSON数组
                var jsonArray = JsonSerializer.Deserialize<List<JsonElement>>(jsonString);
                foreach (var entry in jsonArray) {
                    var processed = ProcessEntry(entry);
                    if (processed != null)
                        activities.AddRange(processed);
                }
            } catch (JsonException) {
                // 逐行解析
                foreach (var line in jsonString.Split('\n')) {
                    var trimmedLine = line.Trim();
                    if (string.IsNullOrEmpty(trimmedLine))
                        continue;

                    try {
                        var entry = JsonSerializer.Deserialize<JsonElement>(trimmedLine);
                        var processed = ProcessEntry(entry);
                        if (processed != null)
                            activities.AddRange(processed);
                    } catch (JsonException) {
                        // 忽略无法解析的行
                    }
                }
            }

            return activities.OrderBy(a => a.Timestamp).ToList();
        }

        private List<ActivityEntry> ProcessEntry(JsonElement entry) {
            try {
                var data = entry.TryGetProperty("data", out var dataElement) ? dataElement : entry;

                if (!data.TryGetProperty("app", out var appElement) ||
                    !data.TryGetProperty("title", out var titleElement))
                    return null;

                var app = appElement.GetString();
                var title = titleElement.GetString();

                if (string.IsNullOrEmpty(app) || string.IsNullOrEmpty(title))
                    return null;

                var duration = entry.TryGetProperty("duration", out var durationElement)
                    ? durationElement.GetDouble() : 0.0;

                if (duration < _config.MinDuration ||
                    _config.ExcludedApps.Contains(app) ||
                    _config.ExcludedTitles.Any(keyword => title.Contains(keyword)))
                    return null;

                var timestampStr = entry.TryGetProperty("timestamp", out var timestampElement)
                    ? timestampElement.GetString() : "";

                var parsedTimestamp = ParseTimestamp(timestampStr);
                if (!parsedTimestamp.HasValue)
                    return null;

                return new List<ActivityEntry>
                {
                    new ActivityEntry
                    {
                        Timestamp = parsedTimestamp.Value,
                        Duration = duration,
                        App = app,
                        Title = title,
                        RawTitle = title
                    }
                };
            } catch (Exception) {
                return null;
            }
        }

        private List<ActivityEntry> ProcessDictionaryEntry(Dictionary<string, object> entry) {
            try {
                Dictionary<string, object> data;

                if (entry.ContainsKey("data")) {
                    if (entry["data"] is JsonElement je && je.ValueKind == JsonValueKind.Object) {
                        // ✅ 将 JsonElement 转为 Dictionary<string, object>
                        data = JsonSerializer.Deserialize<Dictionary<string, object>>(je.GetRawText());
                    } else if (entry["data"] is Dictionary<string, object> dict) {
                        data = dict;
                    } else {
                        return null;
                    }
                } else {
                    data = entry;
                }

                if (!data.ContainsKey("app") || !data.ContainsKey("title"))
                    return null;

                var app = data["app"].ToString();
                var title = data["title"].ToString();

                if (string.IsNullOrEmpty(app) || string.IsNullOrEmpty(title))
                    return null;

                var duration = entry.ContainsKey("duration") ? GetValue<double>(entry["duration"]) : 0.0;

                if (duration < _config.MinDuration ||
                    _config.ExcludedApps.Contains(app) ||
                    _config.ExcludedTitles.Any(keyword => title.Contains(keyword)))
                    return null;

                var timestampStr = entry.ContainsKey("timestamp") ? entry["timestamp"].ToString() : "";
                var parsedTimestamp = ParseTimestamp(timestampStr);
                if (!parsedTimestamp.HasValue)
                    return null;

                return new List<ActivityEntry>
                {
                    new ActivityEntry
                    {
                        Timestamp = parsedTimestamp.Value,
                        Duration = duration,
                        App = app,
                        Title = title,
                        RawTitle = title
                    }
                };
            } catch (Exception e) {
                return null;
            }
        }
        private T GetValue<T>(object value, T defaultValue = default) {
            try {
                if (value == null || value is DBNull)
                    return defaultValue;

                // 处理 JsonElement 特殊情况
                if (value is JsonElement je) {
                    if (typeof(T) == typeof(string)) return (T)(object)je.ToString();
                    if (typeof(T) == typeof(int) && je.TryGetInt32(out var i)) return (T)(object)i;
                    if (typeof(T) == typeof(long) && je.TryGetInt64(out var l)) return (T)(object)l;
                    if (typeof(T) == typeof(double) && je.TryGetDouble(out var d)) return (T)(object)d;
                    if (typeof(T) == typeof(float) && je.TryGetSingle(out var f)) return (T)(object)f;
                    if (typeof(T) == typeof(DateTime) && je.TryGetDateTime(out var dt)) return (T)(object)dt;

                    // fallback: 尝试反序列化整个对象
                    return JsonSerializer.Deserialize<T>(je.GetRawText());
                }

                // 如果已经是目标类型，直接返回
                if (value is T tVal)
                    return tVal;

                // 尝试 Convert.ChangeType
                return (T)Convert.ChangeType(value, typeof(T));
            } catch {
                return defaultValue;
            }
        }

        private List<ActivityEntry> SplitActivityAcrossSlices(ActivityEntry activity, int sliceDurationMinutes) {
            var startTime = activity.Timestamp;
            var duration = activity.Duration;
            var endTime = startTime.AddSeconds(duration);

            var sliceInterval = TimeSpan.FromMinutes(sliceDurationMinutes);

            // 计算开始时间片的边界
            var startSlice = new DateTime(startTime.Year, startTime.Month, startTime.Day,
                startTime.Hour, (startTime.Minute / sliceDurationMinutes) * sliceDurationMinutes, 0);

            // 如果活动完全在一个时间片内，直接返回
            var nextSliceBoundary = startSlice.Add(sliceInterval);
            if (endTime <= nextSliceBoundary)
                return new List<ActivityEntry> { activity };

            // 将活动分割到多个时间片
            var splitActivities = new List<ActivityEntry>();
            var currentSliceStart = startSlice;
            var remainingDuration = duration;

            while (remainingDuration > 0 && currentSliceStart < endTime) {
                var currentSliceEnd = currentSliceStart.Add(sliceInterval);

                // 计算当前时间片中的活动开始时间
                var activityStartInSlice = startTime > currentSliceStart ? startTime : currentSliceStart;
                var activityEndInSlice = endTime < currentSliceEnd ? endTime : currentSliceEnd;

                // 计算在当前时间片中的持续时间
                var durationInSlice = (activityEndInSlice - activityStartInSlice).TotalSeconds;

                if (durationInSlice > 0) {
                    splitActivities.Add(new ActivityEntry {
                        Timestamp = activityStartInSlice,
                        Duration = durationInSlice,
                        App = activity.App,
                        Title = activity.Title,
                        RawTitle = activity.RawTitle
                    });
                }

                currentSliceStart = currentSliceEnd;
                remainingDuration -= durationInSlice;
            }

            return splitActivities;
        }

        /// <summary>
        /// 分析活动数据并生成时间片结果
        /// </summary>
        /// <param name="activities">活动条目列表</param>
        /// <returns>时间片分析结果</returns>
        public List<TimeSliceResult> AnalyzeTimeSlices(List<ActivityEntry> activities) {
            if (!activities.Any())
                return new List<TimeSliceResult>();

            var startTime = activities.First().Timestamp;
            var endTime = activities.Last().Timestamp;
            var interval = _config.TimeSliceMinutes;

            var sliceDict = new Dictionary<DateTime, TimeSliceData>();

            // 分配活动到时间片
            foreach (var activity in activities) {
                var splitActivities = SplitActivityAcrossSlices(activity, interval);

                foreach (var splitActivity in splitActivities) {
                    var sliceKey = new DateTime(splitActivity.Timestamp.Year, splitActivity.Timestamp.Month,
                        splitActivity.Timestamp.Day, splitActivity.Timestamp.Hour,
                        (splitActivity.Timestamp.Minute / interval) * interval, 0);

                    if (!sliceDict.ContainsKey(sliceKey))
                        sliceDict[sliceKey] = new TimeSliceData();

                    var sliceData = sliceDict[sliceKey];
                    sliceData.ActiveSeconds += splitActivity.Duration;

                    if (!sliceData.AppUsage.ContainsKey(splitActivity.App))
                        sliceData.AppUsage[splitActivity.App] = 0;
                    sliceData.AppUsage[splitActivity.App] += splitActivity.Duration;

                    sliceData.WindowTitles.Add(splitActivity.RawTitle);
                    sliceData.Events.Add(splitActivity);

                    // 关键词分析
                    var titleLower = splitActivity.Title.ToLower();
                    if (_config.WorkKeywords.Any(kw => titleLower.Contains(kw.ToLower())))
                        sliceData.KeywordsMatched++;
                    if (_config.DistractionKeywords.Any(kw => titleLower.Contains(kw.ToLower())))
                        sliceData.DistractionCount++;
                }
            }

            // 计算切换次数和主导应用
            foreach (var kvp in sliceDict) {
                var data = kvp.Value;

                // 计算应用切换次数
                if (data.Events.Count > 1) {
                    var prevApp = data.Events[0].App;
                    for (int i = 1; i < data.Events.Count; i++) {
                        if (data.Events[i].App != prevApp)
                            data.SwitchCount++;
                        prevApp = data.Events[i].App;
                    }
                }

                // 确定主导应用
                if (data.AppUsage.Any()) {
                    data.DominantProcess = data.AppUsage.OrderByDescending(x => x.Value).First().Key;
                }
            }

            // 构建最终输出
            var results = new List<TimeSliceResult>();
            var current = new DateTime(startTime.Year, startTime.Month, startTime.Day,
                startTime.Hour, (startTime.Minute / interval) * interval, 0);

            while (current <= endTime) {
                if (sliceDict.ContainsKey(current)) {
                    var data = sliceDict[current];

                    // 计算专注分数
                    var maxSeconds = interval * 60;
                    var timeUtilization = Math.Min(1.0, data.ActiveSeconds / maxSeconds);
                    var switchPenalty = Math.Min(1.0, data.SwitchCount / 10.0);
                    var keywordBoost = Math.Min(0.3, data.KeywordsMatched * 0.1);
                    var distractionPenalty = Math.Min(0.5, data.DistractionCount * 0.2);

                    var focusScore = (timeUtilization * 0.7 + keywordBoost) * (1 - switchPenalty) - distractionPenalty;
                    focusScore = Math.Max(0.0, Math.Min(1.0, focusScore));

                    // 根据阈值确定专注状态
                    var focusState = "无活动";
                    if (data.ActiveSeconds > 0) {
                        var sortedThresholds = _config.FocusThresholds.OrderByDescending(x => x.Value);
                        foreach (var threshold in sortedThresholds) {
                            if (focusScore >= threshold.Value) {
                                focusState = threshold.Key;
                                break;
                            }
                        }
                    }

                    var result = new TimeSliceResult {
                        TimeSlice = current.ToString("yyyy-MM-dd HH:mm"),
                        Timezone = _config.Timezone,
                        DominantProcess = data.DominantProcess ?? "none",
                        ActiveSeconds = Math.Round(data.ActiveSeconds, 1),
                        SwitchCount = data.SwitchCount,
                        KeywordsMatched = data.KeywordsMatched,
                        DistractionEvents = data.DistractionCount,
                        WindowTitles = data.WindowTitles.ToList(),
                        FocusScore = Math.Round(focusScore, 2),
                        FocusState = focusState,
                        ProductivityScore = Math.Round(focusScore * timeUtilization * 100, 1)
                    };

                    if (_config.OutputVerbose) {
                        result.AppUtilization = data.AppUsage.ToDictionary(
                            kvp => kvp.Key,
                            kvp => Math.Round(kvp.Value, 1)
                        );
                    }

                    results.Add(result);
                } else {
                    // 无活动的空时间片
                    results.Add(new TimeSliceResult {
                        TimeSlice = current.ToString("yyyy-MM-dd HH:mm"),
                        Timezone = _config.Timezone,
                        DominantProcess = "none",
                        ActiveSeconds = 0,
                        SwitchCount = 0,
                        KeywordsMatched = 0,
                        DistractionEvents = 0,
                        WindowTitles = new List<string>(),
                        FocusScore = 0.0,
                        FocusState = "无活动",
                        ProductivityScore = 0.0
                    });
                }

                current = current.AddMinutes(interval);
            }

            return results;
        }

        /// <summary>
        /// 完整的分析流程：从ActivityWatchClient数据到时间片结果
        /// </summary>
        /// <param name="rawData">ActivityWatchClient.GetEventsAsync()返回的数据</param>
        /// <returns>时间片分析结果</returns>
        public List<TimeSliceResult> AnalyzeFromRawData(List<Dictionary<string, object>> rawData) {
            var activities = ParseActivityData(rawData);
            return AnalyzeTimeSlices(activities);
        }

        /// <summary>
        /// 将结果保存为JSON文件
        /// </summary>
        /// <param name="results">分析结果</param>
        /// <param name="filePath">输出文件路径</param>
        public async Task SaveResultsToFileAsync(List<TimeSliceResult> results, string filePath) {
            var options = new JsonSerializerOptions {
                WriteIndented = true,
                Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };
            var jsonString = JsonSerializer.Serialize(results, options);
            await File.WriteAllTextAsync(filePath, jsonString);
        }

        /// <summary>
        /// 从配置文件加载配置
        /// </summary>
        /// <param name="configFilePath">配置文件路径</param>
        /// <returns>配置对象</returns>
        public static async Task<ActivityAnalyzerConfig> LoadConfigFromFileAsync(string configFilePath) {
            try {
                var configJson = await File.ReadAllTextAsync(configFilePath);
                return JsonSerializer.Deserialize<ActivityAnalyzerConfig>(configJson);
            } catch (Exception) {
                return new ActivityAnalyzerConfig();
            }
        }
    }
}
