using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using System.Collections.Generic;
using _Combo;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace _Core
{
    public class HttpServer : MonoBehaviour
    {
        private static HttpServer _instance;

        public static HttpServer Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = FindObjectOfType<HttpServer>();
                    if (_instance == null)
                    {
                        GameObject go = new GameObject("HttpServer");
                        _instance = go.AddComponent<HttpServer>();
                    }
                }
                return _instance;
            }
        }

        private HttpListener listener;
        private string contentFilePath;
        private List<string> assetsList;
        private string localIp;
        private bool isServerStart;

        /// <summary>
        /// 获取 HTTP 监听地址
        /// </summary>
        /// <param name="port">端口号</param>
        /// <returns>完整监听地址</returns>
        public static string GetLocalIp(int port)
        {
            return $"http://127.0.0.1:{port}/";
        }

        private void Awake()
        {
            if (_instance == null)
            {
                _instance = this;
                DontDestroyOnLoad(gameObject); // 保证实例在场景切换时不被销毁
            }
            else if (_instance != this)
            {
                Destroy(gameObject); // 保证单例唯一性
            }
        }

        private void OnEnable()
        {
            Application.quitting += OnApplicationQuit;
#if UNITY_EDITOR
            EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
#endif
        }

        private void OnDisable()
        {
            Application.quitting -= OnApplicationQuit;
#if UNITY_EDITOR
            EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
#endif
        }

        /// <summary>
        /// 启动 HTTP 服务器
        /// </summary>
        public void StartServer()
        {
            assetsList = GetComboSDKAssets();
            Log.I($"assetsList.Count = {assetsList.Count}");

            if (listener != null && listener.IsListening)
            {
                isServerStart = true;
                Log.I("HttpServer is already running.");
                return; // 避免重复启动
            }

            contentFilePath = GetPath();
            try
            {
                // 动态获取一个可用端口
                int assignedPort = GetAvailablePort();

                listener = new HttpListener();
                listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;

                // 使用分配的端口
                localIp = GetLocalIp(assignedPort);
                listener.Prefixes.Add(localIp);
                listener.Start();

                listener.BeginGetContext(Response, null);
                isServerStart = true;
                Log.I($"Server started on: {localIp}, game assets: {string.Join(", ", assetsList)}");
            }
            catch (Exception ex)
            {
                isServerStart = false;
                Log.E($"Failed to start server: {ex.Message}");
                var ie = new InternalError(new LocalServerError(ex));
                ErrorTrackingManager.Instance.CaptureException(ie);
            }
        }

        public List<string> GetComboSDKAssetsList()
        {
            return assetsList;
        }

        public string GetLocalPath()
        {
            return localIp.TrimEnd('/');
        }

        public bool IsServerStart()
        {
            return isServerStart;
        }

        /// <summary>
        /// 获取文件路径
        /// </summary>
        /// <returns>完整路径</returns>
        private string GetPath()
        {
            string projectRoot = Application.streamingAssetsPath;
            string relativePath = "ComboSDK";
            string fullPath = Path.Combine(projectRoot, relativePath);
            fullPath = fullPath.Replace("\\", "/");
            return fullPath;
        }

        /// <summary>
        /// 处理 HTTP 请求
        /// </summary>
        private void Response(IAsyncResult ar)
        {
            try
            {
                if (listener == null || !listener.IsListening)
                    return;

                listener.BeginGetContext(Response, null);

                var context = listener.EndGetContext(ar);
                var request = context.Request;
                var response = context.Response;

                string filename = context.Request.Url.AbsolutePath.Trim('/');
                if (string.IsNullOrEmpty(filename))
                {
                    context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                    byte[] errorMsg = Encoding.UTF8.GetBytes("Invalid request");
                    context.Response.OutputStream.Write(errorMsg, 0, errorMsg.Length);
                    context.Response.OutputStream.Close();
                    return;
                }

                filename = Path.Combine(contentFilePath, filename);
                filename = filename.Replace("\\", "/");
                if (!File.Exists(filename))
                {
                    context.Response.StatusCode = (int)HttpStatusCode.NotFound;
                    byte[] errorMsg = Encoding.UTF8.GetBytes("File not found");
                    context.Response.OutputStream.Write(errorMsg, 0, errorMsg.Length);
                    context.Response.OutputStream.Close();
                    return;
                }

                byte[] fileBytes = File.ReadAllBytes(filename);

                context.Response.StatusCode = (int)HttpStatusCode.OK;
                context.Response.ContentLength64 = fileBytes.Length;

                context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
                context.Response.Headers.Add("Cache-Control", "no-cache");

                context.Response.OutputStream.Write(fileBytes, 0, fileBytes.Length);
                context.Response.OutputStream.Close();
            }
            catch (Exception ex)
            {
                Debug.LogError($"An error occurred while processing the request: {ex.Message}");
            }
        }

        /// <summary>
        /// 停止 HTTP 服务器
        /// </summary>
        public void StopServer()
        {
            if (listener != null && listener.IsListening)
            {
                listener.Stop();
                listener.Close();
                listener = null; // 释放资源
                isServerStart = false;
                Log.I($"Server stopped: {DateTime.Now}");
            }
        }

        private void OnApplicationQuit()
        {
            StopServer();
        }

#if UNITY_EDITOR
        private void OnPlayModeStateChanged(PlayModeStateChange state)
        {
            if (state == PlayModeStateChange.ExitingPlayMode)
            {
                StopServer();
            }
        }
#endif

        /// <summary>
        /// 动态获取一个可用的端口号
        /// </summary>
        /// <returns>分配的端口号</returns>
        private int GetAvailablePort()
        {
            TcpListener tcpListener = new TcpListener(IPAddress.Loopback, 0);
            tcpListener.Start();

            int port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
            tcpListener.Stop();
            return port;
        }

        private List<string> GetComboSDKAssets()
        {
            var assets = new List<string>();

            string assetsPath = GetPath();

            // 确保路径存在
            if (Directory.Exists(assetsPath))
            {
                string[] files = Directory.GetFiles(assetsPath, "*", SearchOption.AllDirectories);
                foreach (string file in files)
                {
                    // 检查文件扩展名是否是 .mate
                    if (Path.GetExtension(file) == ".meta")
                    {
                        // 如果是 .mate 文件，跳过
                        continue;
                    }
                    string relativePath = file.Substring(assetsPath.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
                    relativePath = "/" + relativePath.Replace("\\", "/");
                    assets.Add(relativePath);
                }
            }
            else
            {
                Log.I("StreamingAssets/ComboSDK folder does not exist!");
            }

            return assets;
        }
    }
}
