using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using LJLib.Net.SPI.Com;
using LJLib.Net.SPI.Server;
using LJLib.Text.Parser;
using LJLib.Tools.Helper;
using LJLib.Tools.Utils;
using JLHHJSvr.LJLib.HttpServer;
using System.Web;
using System.Linq;
using Newtonsoft.Json;

namespace LJLib.HttpServer
{
    public class SimpleHttpServer : LJHttpServer
    {
        private ILJServer server;
        private IFileDBModel fileModel;
        private static LJParser parser = new LJParser();
        private static Dictionary<string, byte[]> files = new Dictionary<string, byte[]>();

        public SimpleHttpServer(int port, ILJServer server, IFileDBModel fileModel)
            : base(port)
        {
            this.server = server;
            this.fileModel = fileModel;
        }

        public override void HandleGetRequest(LJHttpProcessor p)
        {
            //转到POST统一处理
            HandlePostRequest(p, null);
        }

        public override void HandlePostRequest(LJHttpProcessor p, StreamReader inputData)
        {
            string bufferedBody = string.Empty;
            if (inputData != null)
            {
                bufferedBody = inputData.ReadToEnd();
            }
            if (p.http_method.Equals("POST"))
            {
                if (p.http_url.StartsWith("/api.ashx"))
                {
                    if (server == null)
                    {
                        throw new Exception("未定义server成员");
                    }
                    var postParamDic = p.POSTqueryParams(inputData);
                    if (!postParamDic.ContainsKey("method"))
                    {
                        p.WriteError("无效的请求接口");
                        return;
                    }
                    string method = postParamDic["method"];//接口名称apiName
                    string requestbody = string.Empty;//请求类JSON字符串
                    if (postParamDic.ContainsKey("requestbody"))
                    {
                        requestbody = postParamDic["requestbody"];
                    }
                    // 处理请求
                    handleAPI(p, method, requestbody);
                    return;
                }
                else if (p.http_url.StartsWith("/api/common/"))
                {
                    var apiName = p.http_url.Substring(12);
                    var requestbody = bufferedBody;
                    handleAPI(p, apiName, requestbody);
                    return;
                }
            }
            else if (p.http_method.Equals("GET"))
            {
                // 图片/文件获取接口
                if (p.http_url.StartsWith("/img.ashx"))
                {
                    var parms = p.GETqueryParams();
                    string filemd5 = string.Empty;
                    if (!parms.ContainsKey("filename"))
                    {
                        Trace.Write("请求img.ashx不包含filename参数");
                    }
                    else
                    {
                        filemd5 = parms["filename"];
                    }

                    byte[] body = null;
                    if (files.ContainsKey(filemd5))
                    {
                        body = files[filemd5];
                    }
                    else
                    {
                        body = fileModel.GetBytes(filemd5);
                    }

                    var ext = MIMEHelper.GetExType(body);
                    var contentType = MIMEHelper.ContentType("." + ext);

                    if (!string.IsNullOrEmpty(ext) && parms.ContainsKey("w") && parms.ContainsKey("h"))
                    {
                        int width;
                        int height;

                        if (int.TryParse(parms["w"], out width) && int.TryParse(parms["h"], out height))
                        {
                            using (var ms = new MemoryStream(body))
                            using (var img = Image.FromStream(ms))
                            using (var oImg = ImgHelper.NewBMPFrom(img, width, height))
                            using (var oms = new MemoryStream())
                            {
                                oImg.Save(oms, ImageFormat.Png);
                                body = oms.ToArray();
                                contentType = MIMEHelper.ContentType(".png");
                            }
                        }
                    }
                    p.WriteResponse(body, contentType);
                    return;
                }
                else if (p.http_url.StartsWith("/dist") || p.http_url.StartsWith("/html") ||
                         p.http_url.StartsWith("/App_Files"))
                {
                    string basePath = AppDomain.CurrentDomain.BaseDirectory;
                    string requestPath;
                    requestPath = p.http_url.Substring(1);
                    string filePath = basePath + "/" + requestPath;
                    if (!File.Exists(filePath))
                    {
                        p.WriteError("未找到文件");
                        return;
                    }
                    string fileName = p.http_url.Substring(p.http_url.LastIndexOf('.')).ToLower();
                    string fileType = MIMEHelper.ContentType(fileName);

                    byte[] body;
                    using (var ms = new MemoryStream())
                    using (var fs = File.OpenRead(filePath))
                    {
                        StreamHelper.StreamCopy(ms, fs);
                        body = ms.ToArray();
                    }

                    if (fileType.StartsWith("text/html"))
                    {
                        fileType += "; charset=utf-8";
                    }
                    p.WriteResponse(Encoding.UTF8.GetString(body), fileType);
                    return;
                }
                else
                {
                    string basePath = AppDomain.CurrentDomain.BaseDirectory;
                    string filePath = basePath + "/App_Files/";
                    var sourceDir = new DirectoryInfo(filePath);
                    var enabledSubWeb = sourceDir.GetDirectories().Select(x => x.Name);
                    var subUrl = p.http_url;
                    var subDirs = subUrl.Split('/').Where(x => !string.IsNullOrEmpty(x)).ToList();
                    var subDir = "Web";
                    if (subDirs.Any())
                    {
                        if (enabledSubWeb.Contains(subDirs.First()))
                        {
                            subDir = subDirs.First();
                            var firstblock = $"/{subDir}/";
                            var removeidx = subUrl.IndexOf(firstblock);
                            subUrl = subUrl.Substring(removeidx + firstblock.Length - 1);
                        }
                    }
                    filePath += subDir;

                    if (subUrl.IndexOf(".") > 0)
                    {
                        if (File.Exists(filePath + subUrl))
                        {
                            filePath += subUrl;
                        }
                        else
                        {
                            filePath += "/index.html";
                        }
                    }
                    else
                    {
                        filePath += "/index.html";
                    }
                    if (!File.Exists(filePath))
                    {
                        p.WriteResponse(
                        new[]
                        {
                            "HTTP/1.0 404 Not Found",
                            "Content-Type: text/plain",
                            "Connection: close"
                        }, "The resource you requested ('" + p.http_url + "') could not be found.");
                    }
                    else
                    {
                        byte[] body;
                        string fileType = null;
                        string ext = null;
                        if (filePath.Contains("."))
                        {
                            ext = filePath.Substring(filePath.LastIndexOf("."));
                            fileType = MIMEHelper.ContentType(ext);
                        }
                        using (var ms = new MemoryStream())
                        using (var fs = File.OpenRead(filePath))
                        {
                            StreamHelper.StreamCopy(ms, fs);
                            body = ms.ToArray();
                            if (string.IsNullOrEmpty(fileType))
                            {
                                ext = MIMEHelper.GetExType(body);
                                fileType = MIMEHelper.ContentType("." + ext);
                            }
                        }

                        if (fileType.StartsWith("text/html"))
                        {
                            fileType += "; charset=utf-8";
                            p.WriteResponse(new[]
                            {
                                "HTTP/1.0 200 OK",
                                "Content-Type: " + fileType,
                                "Connection: close"
                            }, Encoding.UTF8.GetString(body));
                        }
                        else
                        {
                            p.WriteResponse(new[]
                            {
                                "HTTP/1.0 200 OK",
                                "Content-Type: " + fileType,
                                "Content-Length: " + body.Length,
                                "Connection: close"
                            }, body);
                        }
                    }

                    return;
                }
            }
            p.WriteFailure();
        }

        private void handleAPI(LJHttpProcessor p, string method, string requestbody)
        {
            LJResponse responselist = null;
            string str = string.Empty;
            perf_event_log perf = null;
            var dataArriveTime = DateTime.Now; // 接口处理开始
            try
            {
                if (!requestbody.StartsWith("{"))
                {
                    requestbody = HttpUtility.UrlDecode(requestbody);
                    if (!requestbody.StartsWith("{"))
                    {
                        Trace.Write("请求格式错误" + requestbody);
                        throw new Exception("请求格式错误");
                    }
                }

                ILJRequest requestlist = null;
                string apiName = method;
                Type requestType = server.GetRequestType(apiName);
                string body = requestbody;

                requestlist = JsonConvert.DeserializeObject(body, requestType) as ILJRequest;
                //requestlist = parser.JsonParse(requestType, body) as ILJRequest;

                var dataReadTime = DateTime.Now; // 请求解析完成
                responselist = server.DoExcute(requestlist, null);
                var doneTime = DateTime.Now; // 接口处理完成

                if (!string.IsNullOrEmpty(responselist.ErrMsg))
                {
                    Trace.Write(requestlist.GetApiName() + ":" + responselist.ErrMsg);
                }

                perf = requestlist.perf;
                if (perf != null)
                {
                    perf.EventName = requestlist.GetApiName();
                    if (perf.clientinfo == null)
                    {
                        perf.clientinfo = string.Empty;
                    }
                    if (perf.dtList == null)
                    {
                        perf.dtList = string.Empty;
                    }

                    perf.clientinfo += "http\r\n";

                    perf.dtList += $"{dataArriveTime:yyyy-MM-dd HH:mm:ss.fff} 接口处理开始\r\n"; // 2. 接收：数据到达
                    perf.dtList += $"{dataReadTime:yyyy-MM-dd HH:mm:ss.fff} 请求解析完成\r\n"; // 3. 解析: 读数完成转LJRequest
                    perf.dtList += $"{doneTime:yyyy-MM-dd HH:mm:ss.fff} 接口处理完成\r\n"; // 4. 后台处理: 解析完进行处理
                }

                responselist.perf = perf;

                //Dictionary<string, byte[]> fil = new Dictionary<string, byte[]>();
                //str = parser.ToJson(responselist, fil, "/img.ashx?filename=");

                str = JsonConvert.SerializeObject(responselist);
            }
            catch (Exception ex)
            {
                Trace.Write(ex.ToString());
                responselist = new ErrResponse(ex.ToString());
                str = parser.ToJson(responselist);
            }

            p.WriteResponse(
                new[]{
                    "HTTP/1.0 200 OK",
                    "Content-Type: text/plain; charset=utf-8",
                    "Connection: close"
                },
                str);
        }
    }
}