using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEngine;

namespace UnityAssistant
{
    public static class BuildTools
    {
        public static string GetBuildSettings(Dictionary<string, object> args)
        {
            var target = EditorUserBuildSettings.activeBuildTarget;
            var group = EditorUserBuildSettings.selectedBuildTargetGroup;
            var scenes = EditorBuildSettings.scenes;

            var sceneRows = new List<object>();
            foreach (var scene in scenes)
            {
                sceneRows.Add(new Dictionary<string, object>
                {
                    { "path", scene.path },
                    { "enabled", scene.enabled }
                });
            }

            var payload = new Dictionary<string, object>
            {
                { "ok", true },
                { "active_target", target.ToString() },
                { "target_group", group.ToString() },
                { "development_build", EditorUserBuildSettings.development },
                { "scenes", sceneRows },
                { "product_name", Application.productName },
                { "company_name", Application.companyName }
            };
            return JsonUtil.ToJson(payload);
        }

        public static string SetBuildTarget(Dictionary<string, object> args)
        {
            string targetName = JsonUtil.Get(args, "target").Trim();
            if (string.IsNullOrEmpty(targetName))
                return "{\"ok\":false,\"error\":\"missing target\"}";

            if (!Enum.TryParse(targetName, true, out BuildTarget target))
                return JsonUtil.ToJson(new Dictionary<string, object> { { "ok", false }, { "error", "unknown build target: " + targetName } });

            var group = BuildPipeline.GetBuildTargetGroup(target);
            if (group == BuildTargetGroup.Unknown)
                return JsonUtil.ToJson(new Dictionary<string, object> { { "ok", false }, { "error", "build target group is unknown for " + target } });

            bool ok = EditorUserBuildSettings.SwitchActiveBuildTarget(group, target);
            return ok
                ? "{\"ok\":true,\"active_target\":" + JsonUtil.Quote(target.ToString()) + ",\"target_group\":" + JsonUtil.Quote(group.ToString()) + "}"
                : JsonUtil.ToJson(new Dictionary<string, object> { { "ok", false }, { "error", "Unity could not switch to " + target } });
        }

        public static string TriggerBuild(Dictionary<string, object> args)
        {
            var scenes = EnabledBuildScenes();
            if (scenes.Count == 0)
                return "{\"ok\":false,\"error\":\"no enabled scenes in Build Settings\"}";

            bool development = JsonUtil.GetBool(args, "development", EditorUserBuildSettings.development);
            string outputPath = JsonUtil.Get(args, "output_path", "Builds");
            if (string.IsNullOrWhiteSpace(outputPath)) outputPath = "Builds";

            var target = EditorUserBuildSettings.activeBuildTarget;
            var group = BuildPipeline.GetBuildTargetGroup(target);
            string locationPathName = ResolveBuildLocation(outputPath, target);
            Directory.CreateDirectory(Path.GetDirectoryName(locationPathName));

            var options = new BuildPlayerOptions
            {
                scenes = scenes.ToArray(),
                locationPathName = locationPathName,
                target = target,
                targetGroup = group,
                options = development ? BuildOptions.Development : BuildOptions.None
            };

            BuildReport report = BuildPipeline.BuildPlayer(options);
            BuildSummary summary = report.summary;
            bool succeeded = summary.result == BuildResult.Succeeded;

            var payload = new Dictionary<string, object>
            {
                { "ok", succeeded },
                { "result", summary.result.ToString() },
                { "active_target", target.ToString() },
                { "total_errors", summary.totalErrors },
                { "total_warnings", summary.totalWarnings },
                { "total_size", (long)summary.totalSize },
                { "duration_seconds", summary.totalTime.TotalSeconds },
                { "output_path", summary.outputPath }
            };
            if (!succeeded) payload["error"] = "build failed: " + summary.result;
            return JsonUtil.ToJson(payload);
        }

        private static List<string> EnabledBuildScenes()
        {
            var scenes = new List<string>();
            foreach (var scene in EditorBuildSettings.scenes)
            {
                if (scene.enabled && !string.IsNullOrEmpty(scene.path)) scenes.Add(scene.path);
            }
            return scenes;
        }

        private static string ResolveBuildLocation(string outputPath, BuildTarget target)
        {
            string root = Directory.GetCurrentDirectory();
            string normalized = outputPath.Replace('\\', '/').Trim();
            string projectRelative = Path.IsPathRooted(normalized)
                ? normalized
                : Path.Combine(root, normalized);

            string extension = Path.GetExtension(projectRelative);
            bool pointsToFile = !string.IsNullOrEmpty(extension);
            if (pointsToFile) return projectRelative;

            string productName = SanitizeFileName(Application.productName);
            if (string.IsNullOrEmpty(productName)) productName = "UnityBuild";

            string fileName = productName;
            if (target == BuildTarget.StandaloneWindows || target == BuildTarget.StandaloneWindows64) fileName += ".exe";
            else if (target == BuildTarget.StandaloneOSX) fileName += ".app";
            else if (target == BuildTarget.Android) fileName += ".apk";

            return Path.Combine(projectRelative, fileName);
        }

        private static string SanitizeFileName(string value)
        {
            foreach (char invalid in Path.GetInvalidFileNameChars())
            {
                value = value.Replace(invalid.ToString(), "");
            }
            return value.Trim();
        }
    }
}
