using BestHTTP;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using System.Security.Cryptography;
using System.IO;
using UnityEngine.Networking;
using UnityEngine.EventSystems;
using AX.MessageSystem;

#region 接口数据类型
#pragma warning disable IDE1006 // 命名样式
[Serializable]
public class DeviceObjConfig
{
    public string ObjName;
    public string DeviceId;
}
/// <summary>
/// HTTP通信错误信息类
/// </summary>
public class ProblemDetails
{
    public string type;
    public string title;
    public int status;
    public string detail;
    public string instance;
}
public class diveceSourceData
{
    public int currentPage;
    public int pageSize;
    public long buildingId;
    public string deviceTypes;
    public string sign;
    public long timestamp;
}
public class diveceAlarmData
{
    public int currentPage;
    public int pageSize;
    public long buildingId;
    public string type;//fire fault type事件类型(fire=火警, fault=故障)
    public string sign;
    public long timestamp;
}
[Serializable]
public class PageInfoList<T>
{
    public int? endRow { get; set; }
    public bool? hasNextPage { get; set; }
    public bool? hasPreviousPage { get; set; }
    public bool? isFirstPage { get; set; }
    public bool? isLastPage { get; set; }
    /// <summary>
    /// 数据
    /// </summary>
    public List<T> list { get; set; }
    public int? navigateFirstPage { get; set; }
    public int? navigateLastPage { get; set; }
    public int? navigatePages { get; set; }
    public List<int> navigatepageNums { get; set; }
    public int? nextPage { get; set; }
    public int? pageNum { get; set; }
    public int? pageSize { get; set; }
    public int? pages { get; set; }
    public int? prePage { get; set; }
    public int? size { get; set; }
    public int? startRow { get; set; }
    public int? total { get; set; }

}
[Serializable]
public class TotaDivecelInfo
{
    /// <summary>
    /// 状态码
    /// </summary>
    public int? code { get; set; }
    /// <summary>
    /// 数据
    /// </summary>
    public PageInfoList<DeviceList> data { get; set; }
    /// <summary>
    /// 消息
    /// </summary>
    public string message { get; set; }
}
[Serializable]
public class DeviceList
{
    /// <summary>
    /// 创建时间
    /// </summary>
    public string createTime { get; set; }
    /// <summary>
    /// 点位或者设备的位置描述
    /// </summary>
    public string descript { get; set; }
    /// <summary>
    /// 设备名称
    /// </summary>
    public string deviceName { get; set; }
    /// <summary>
    /// 设备唯一编号
    /// </summary>
    public string deviceNo { get; set; }
    /// <summary>
    /// 设备类型code(参照设备类型字典表)
    /// </summary>
    public int? deviceType { get; set; }
    /// <summary>
    /// 设备类型名称(参照设备类型字典表)
    /// </summary>
    public string deviceTypeName { get; set; }
    /// <summary>
    /// 楼层
    /// </summary>
    public string floor { get; set; }
    /// <summary>
    /// 编号
    /// </summary>
    public string id { get; set; }
    /// <summary>
    /// 更新时间
    /// </summary>
    public string modifyTime { get; set; }
    /// <summary>
    /// 二级平台对应的项目id
    /// </summary>
    public string openProjectId { get; set; }
    /// <summary>
    /// 点位号
    /// </summary>
    public string pointNumber { get; set; }
    /// <summary>
    /// 数据提供者物联网的唯一标志id
    /// </summary>
    public string provideKey { get; set; }
    /// <summary>
    /// 状态
    /// </summary>
    public int? status { get; set; }
    /// <summary>
    /// 设备大类型名称
    /// </summary>
    public int? stype { get; set; }
    /// <summary>
    /// 设备大类型名称
    /// </summary>
    public string stypeName { get; set; }
    /// <summary>
    /// 系统id
    /// </summary>
    public string sysId { get; set; }
    /// <summary>
    /// 系统名称
    /// </summary>
    public string sysName { get; set; }
    /// <summary>
    /// 设备及时数据
    /// </summary>
    public object timelyData { get; set; }
    /// <summary>
    /// 防火/防烟分区
    /// </summary>
    public string zone { get; set; }

}
[Serializable]
public class TotaDivecelAlarmInfo
{
    /// <summary>
    /// 状态码
    /// </summary>
    public int? code { get; set; }
    /// <summary>
    /// 数据
    /// </summary>
    public PageInfoList<DeviceAlarmList> data { get; set; }
    /// <summary>
    /// 消息
    /// </summary>
    public string message { get; set; }
}
[Serializable]
public class DeviceAlarmList
{
    public string alarmTime;
    public string createTime;
    public string descript;
    public string deviceName;
    public string deviceNo;
    public int deviceType;
    public string deviceTypeName;
    public string handleAlarmTime;
    public string handlePeople;
    public string handlePhone;
    public string id;
    public string modifyTime;
    public int state;
    public int status;
}
#pragma warning restore IDE1006 // 命名样式
#endregion
//diviceid(136-用户信息传输装置, 258-消防水泵状态, 401-消防水箱水位,
//302-消防主管网压力, 305-消火栓末端压力, 256-喷淋泵, 301-喷淋主管网压力,
//304-喷淋末端压力, 451-正压送风机, 452-防火排烟风机, 453-补风机)

//manualAutomaticState 手自动状态(0 自动,1 手动) TRUE string
//powerState 电源状态(0 已上电,1 未上电) TRUE string
//faultStatus 故障信息(0 正常,1 故障) TRUE string
//startStopStatus 启停状态(0 停止,1 启动) TRUE string
public enum DeviceType
{
    空 = 0,
    水泵 = 258,//
    喷淋泵 = 256,//
    水箱 = 401,//  
    消火栓末端 = 305,//
    喷淋末端 = 304,//
    喷淋主管网 = 301,//
    消防主管网 = 302,//
    送风机 = 451,
    排烟风机 = 452,
    补风机 = 453,
}
public class DevicePanelManager : MonoBehaviour
{
    public static DevicePanelManager Instance;
    public GameObject DeviceBindPrefab;
    #region 对接数据相关
    private string baseHttpUrl = "/api/iot/open/device/point/iot/data/device/list";
    private diveceSourceData postData;
    private const string key = "2f88b96ff4ac43b4bfbd2b5f99610a01";
    private const string secret = "ccb53d34773a43069d17e2c6d3cfd0d1";
    private int currentpage = 1;
    private int pageSize = 100000;
    private long buildId = 1162809597414907904;//凯德虹口商业中心--大型城市综合体
    private long buildId1 = 1162809590251036672;//凯德虹口商业中心-超高层
    //服务端获取全部数据
    public List<KeyValuePair<DeviceType, List<DeviceList>>> AllData = new List<KeyValuePair<DeviceType, List<DeviceList>>>();
    public DeviceType textType;
    private bool getDataError = false;
    private float timmer = 0;
    #endregion
    #region 本地数据绑定
    public List<DeviceObjConfig> BindObjectList = new List<DeviceObjConfig>();
    public DeviceObj NowClickObject;
    public DeviceType NowType;
    private string objId = "binddataid";
    #region 创建绑定点位
    public bool CanClone = false;
    public DeviceType MenuType;
    public LayerMask layerMask = -1;
    private float DistanceY = 0;
    public Transform CloneParent;
    public GameObject ClonePrefab;
    #endregion
    #endregion
    void Awake()
    {
        MessageDispatcher.AddListener("ConfigLoadOver", ConfigLoadOver);
        Instance = this;
    }
    private void Start()
    {

    }
    private void OnDestroy()
    {
        MessageDispatcher.RemoveListener("ConfigLoadOver", ConfigLoadOver);
    }
    private void ConfigLoadOver(IMessage obj)
    {
        LoadDeciceData();
        LoadDeviceObjConfig();
    }

    public void RefreshAllData()
    {
        StopAllCoroutines();
        LoadDeciceData();
    }
    public void RefreshData(string deviceNo)
    {
        StopAllCoroutines();
        LoadDeciceData(deviceNo);
    }
    public DeviceList GetDeviceData(string deviceNo)
    {
        DeviceList data = null;
        foreach (var item in AllData)
        {
            foreach (var value in item.Value)
            {
                if (value.deviceNo == deviceNo)
                {
                    data = value;
                    break;
                }
            }
        }
        return data;
    }
    private void LoadDeciceData(string deviceNo = null)
    {
        if (deviceNo == null)
        {
            AllData.Clear();
            foreach (DeviceType i in Enum.GetValues(typeof(DeviceType)))
            {
                if (i != DeviceType.空)
                {
                    KeyValuePair<DeviceType, List<DeviceList>> info = new KeyValuePair<DeviceType, List<DeviceList>>(
                        i, new List<DeviceList>());
                    AllData.Add(info);
                }
            }
        }
        foreach (var item in AllData)
        {
            int iType = (int)item.Key;
            LoadDiviceData(buildId, iType.ToString(), item.Key, deviceNo);
            LoadDiviceData(buildId1, iType.ToString(), item.Key, deviceNo);
        }
    }
    private void LateUpdate()
    {
        //if (Input.GetKeyDown(KeyCode.T))
        //{
        //    ShowBindList(textType);
        //}
        if (Input.GetKey(KeyCode.Q))
        {
            if (Input.GetKeyDown(KeyCode.P))
            {
                CanClone = true;
            }
            if (Input.GetKeyDown(KeyCode.S))
            {
                DeviceObjManager.Instance.SaveObjs();
            }
        }
        if (CanClone)
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, layerMask))
            {
                if (!EventSystem.current.IsPointerOverGameObject())
                {
                    if (Input.GetMouseButtonDown(0) && hit.collider.GetComponent<InstantiateData>())
                    {
                        CreatePoint(hit.point, hit.collider.GetComponent<InstantiateData>().floorId);
                    }
                }
                if (Input.GetMouseButtonDown(1))
                {
                    CanClone = false;
                }
            }
        }
        if (getDataError == true)
        {
            timmer += Time.deltaTime;
            if (timmer >= 60)
            {
                timmer = 0;
                getDataError = false;
                RefreshAllData();
                Debug.LogWarning("从对方服务器获取数据错误!");
            }
        }
    }
    private void CreatePoint(Vector3 position, int floorId)
    {
        var pos = new Vector3(position.x, position.y + DistanceY, position.z);

        var go = Instantiate(ClonePrefab, pos, Quaternion.identity, CloneParent);
        go.name = $"{MenuType}{AX.Network.Common.GUID.NewGuid()}";
        if (go.GetComponent<DeviceObj>())
        {
            go.GetComponent<DeviceObj>().CreateIcon(MenuType, floorId);
        }
        SelectionManager.Instance.Sets.Add(go);
    }
    public void ShowBindList(DeviceType type)
    {
        StopAllCoroutines();
        MenuType = type;
        NowClickObject = null;
        NowType = type;
        if (type != DeviceType.空)
        {
            List<DeviceList> infoList = new List<DeviceList>();
            foreach (var item in AllData)
            {
                if (item.Key == type)
                {
                    foreach (var value in item.Value)
                    {
                        infoList.Add(value);
                    }
                    break;
                }
            }
            BindDeviceList(type, infoList);
        }
        else
        {
            foreach (Transform item in transform)
            {
                item.gameObject.SetActive(false);
            }
        }
    }
    public void ShowBindList(DeviceType type, DeviceObj selectObject)
    {
        NowClickObject = selectObject;
        NowType = type;
        if (type != DeviceType.空)
        {
            List<DeviceList> infoList = new List<DeviceList>();
            foreach (var item in AllData)
            {
                if (item.Key == type)
                {
                    foreach (var value in item.Value)
                    {
                        infoList.Add(value);
                    }
                    break;
                }
            }
            BindDeviceList(type, infoList);
        }
        else
        {
            foreach (Transform item in transform)
            {
                item.gameObject.SetActive(false);
            }
        }
    }
    private void BindDeviceList(DeviceType type, List<DeviceList> bindData)
    {
        bool has = false;
        foreach (Transform item in transform)
        {
            if (item.GetComponent<DeviceBind>() && item.GetComponent<DeviceBind>().BindType == type)
            {
                item.GetComponent<DeviceBind>().DataBind(type, bindData, null == NowClickObject ? null : NowClickObject.name);
                has = true;
            }
            else
            {
                item.gameObject.SetActive(false);
            }
        }
        if (!has)
        {
            var go = Instantiate(DeviceBindPrefab, transform);
            go.name = type.ToString();
            go.GetComponent<DeviceBind>().DataBind(type, bindData, null == NowClickObject ? null : NowClickObject.name);
        }
    }
    private void LoadDiviceData(long buildId, string diviceId, DeviceType type, string deviceNo = null)
    {
        using (MD5 md5Hash = MD5.Create())
        {
            postData = new diveceSourceData();
            postData.currentPage = currentpage;
            postData.pageSize = pageSize;
            postData.buildingId = buildId;
            postData.deviceTypes = diviceId;
            postData.timestamp = DateTime.Now.Ticks / 10000;
            string signstr = $"buildingId={postData.buildingId}&currentPage={postData.currentPage}" +
                $"&deviceTypes={postData.deviceTypes}&pageSize={postData.pageSize}" +
                $"&timestamp={postData.timestamp}&secret={secret}";
            byte[] signbyte = Encoding.UTF8.GetBytes(signstr);
            byte[] signmdbyte = md5Hash.ComputeHash(signbyte);
            string StrResult = BitConverter.ToString(signmdbyte);
            StrResult = StrResult.Replace("-", "").ToLower();
            postData.sign = StrResult;
            //Debug.Log($"sign is:" + postData.sign);
            if (Application.platform == RuntimePlatform.WebGLPlayer)
            {
                Post<diveceSourceData, TotaDivecelInfo>($"{baseHttpUrl}?appKey={key}", postData, (d) =>
                {
                    //Debug.Log(d.code);
                    if (d.code != 200)
                    {
                        getDataError = true;
                        return;
                    }
                    if (deviceNo == null)
                    {
                        foreach (var item in d.data.list)
                        {
                            foreach (var data in AllData)
                            {
                                if (data.Key == type)
                                {
                                    data.Value.Add(item);
                                }
                            }
                        }
                    }
                    else
                    {
                        foreach (var item in d.data.list)
                        {
                            if (item.deviceNo == deviceNo)
                            {
                                foreach (var data in AllData)
                                {
                                    if (data.Key == type)
                                    {
                                        for (int i = 0; i < data.Value.Count; i++)
                                        {
                                            if (data.Value[i].deviceNo == deviceNo)
                                            {
                                                data.Value[i] = item;
                                                Debug.Log("数据刷新成功!");
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }, (a, b) =>
                {
                    Debug.LogError(a + b);
                    getDataError = true;
                });
            }
            else
            {
                PostJson<diveceSourceData, TotaDivecelInfo>($"?appKey={key}", postData, (d) =>
                {
                    //Debug.Log(d.code);
                    if (d.code != 200)
                    {
                        getDataError = true;
                        return;
                    }
                    if (deviceNo == null)
                    {
                        foreach (var item in d.data.list)
                        {
                            foreach (var data in AllData)
                            {
                                if (data.Key == type)
                                {
                                    data.Value.Add(item);
                                }
                            }
                        }
                    }
                    else
                    {
                        foreach (var item in d.data.list)
                        {
                            if (item.deviceNo == deviceNo)
                            {
                                foreach (var data in AllData)
                                {
                                    if (data.Key == type)
                                    {
                                        for (int i = 0; i < data.Value.Count; i++)
                                        {
                                            if (data.Value[i].deviceNo == deviceNo)
                                            {
                                                data.Value[i] = item;
                                                Debug.Log("数据刷新成功!");
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }, (a, b) =>
                {
                    Debug.LogError(a + b);
                    getDataError = true;
                });
            }
        }
    }
    public void Post<Tin, Tout>(string url, Tin obj, Action<Tout> action = null, Action<int, string> error = null)
    {
        StartCoroutine(PostCoroutine(url, obj, action, error));
        Debug.Log("web gl");
    }
    private IEnumerator PostCoroutine<Tin, Tout>(string url, Tin obj, Action<Tout> action = null, Action<int, string> error = null)
    {
        string jsonParam = JsonConvert.SerializeObject(obj);
        byte[] body = Encoding.UTF8.GetBytes(jsonParam);
        UnityWebRequest uwr = new UnityWebRequest(url, "POST");
        uwr.uploadHandler = new UploadHandlerRaw(body);

        uwr.SetRequestHeader("Content-Type", "application/json;charset=utf-8");
        uwr.SetRequestHeader("dev", "open_service");

        DownloadHandler downloadHandler = new DownloadHandlerBuffer();
        uwr.downloadHandler = downloadHandler;

        yield return uwr.SendWebRequest();
        if (uwr.isHttpError || uwr.isNetworkError)
        {
            Debug.Log(uwr.error);
            error?.Invoke((int)uwr.responseCode, uwr.error);
        }
        else
        {
            Debug.Log(uwr.downloadHandler.text);
            Tout result = JsonConvert.DeserializeObject<Tout>(uwr.downloadHandler.text);
            action?.Invoke(result);
        }
    }
    /// <summary>
    /// 提交json数据
    /// </summary>
    /// <typeparam name="TIn">提交数据类型</typeparam>
    /// <typeparam name="TOut">返回数据类型</typeparam>
    /// <param name="apiUrl">API URL</param>
    /// <param name="data">提交数据</param>
    /// <param name="success">请求成功回调</param>
    /// <param name="error">请求错误回调</param>
    public void PostJson<TIn, TOut>(string apiUrl, TIn data, Action<TOut> success, Action<int, string> error = null)
    {
        Debug.Log("windows");
        if (string.IsNullOrEmpty(apiUrl))
        {
            throw new ArgumentNullException($"API URL:{apiUrl}无效!");
        }
        string str = "http://39.108.36.226:81";
        Debug.Log("httpUrl is :" + str + baseHttpUrl + apiUrl);
        var url = new Uri(str + baseHttpUrl + apiUrl);
        HTTPRequest request = new HTTPRequest(url, HTTPMethods.Post, (req, resp) =>
        {
            Debug.Log(url.Host + url.Port);
            switch (req.State)
            {
                case HTTPRequestStates.Finished:
                    if (resp.IsSuccess)
                    {
                        TOut result = JsonConvert.DeserializeObject<TOut>(resp.DataAsText);
                        success?.Invoke(result);
                    }
                    else
                    {
                        Debug.LogWarning(string.Format("Request finished Successfully, but the server sent an error. Status Code: {0}-{1} Message: {2}",
                                                        resp.StatusCode,
                                                        resp.Message,
                                                        resp.DataAsText));
                        error?.Invoke(resp.StatusCode, JsonConvert.DeserializeObject<ProblemDetails>(resp.DataAsText).detail);
                    }
                    break;
                case HTTPRequestStates.Error:
                    Debug.LogError("Request Finished with Error! " + (req.Exception != null ? (req.Exception.Message + "\n" + req.Exception.StackTrace) : "No Exception"));
                    error?.Invoke((int)HTTPRequestStates.Error, "Request Finished with Error!");
                    break;
                case HTTPRequestStates.Aborted:
                    Debug.LogWarning("Request Aborted!");
                    error?.Invoke((int)HTTPRequestStates.Aborted, "Request Aborted!");
                    break;
                case HTTPRequestStates.ConnectionTimedOut:
                    Debug.LogError("Connection Timed Out!");
                    error?.Invoke((int)HTTPRequestStates.ConnectionTimedOut, "Connection Timed Out!");
                    break;
                case HTTPRequestStates.TimedOut:
                    Debug.LogError("Processing the request Timed Out!");
                    error?.Invoke((int)HTTPRequestStates.TimedOut, "Processing the request Timed Out!");
                    break;
            }
        });

        //request.SetHeader("Authorization", "Bearer " + identityInfo.token);
        request.SetHeader("Content-Type", "application/json; charset=UTF-8");
        request.SetHeader("dev", "open_service");
        string json = JsonConvert.SerializeObject(data);
        request.RawData = Encoding.UTF8.GetBytes(json);

        request.Send();
    }

    private void LoadDeviceObjConfig()
    {
        try
        {
            string url = string.Format(HttpManager.Instance.GetOilTankById, objId);
            Debug.Log($"the url is :{ url}");
            if (Application.platform == RuntimePlatform.WebGLPlayer)
            {
                url = url.Substring(url.IndexOf("api") - 1);
            }
            HttpManager.Instance.Get<string>(url, d =>
            {
                //Debug.Log("aaaaaaaaaaaaaaaaaaaaaa:" + d);
                BindObjectList = JsonConvert.DeserializeObject<List<DeviceObjConfig>>(d);
            });
        }
        catch
        {
            Debug.LogError("暂无数据!");
        }
    }
    public void SaveDeviceObjConfig(DeviceObjConfig config)
    {
        bool has = false;
        foreach (var item in BindObjectList)
        {
            if (item.DeviceId == config.DeviceId)
            {
                item.ObjName = config.ObjName;
                has = true;
                break;
            }
        }
        if (!has)
        {
            BindObjectList.Add(config);
        }
        string bindName = "";
        foreach (Transform ts in DeviceObjManager.Instance.transform)
        {
            if (ts.name == config.ObjName)
            {
                bindName = ts.name;
                break;
            }
        }
        if (!string.IsNullOrEmpty(bindName))
        {
            DeviceObjManager.Instance.AddObj(bindName);
        }
        var json = JsonConvert.SerializeObject(BindObjectList);
        string url = string.Format(HttpManager.Instance.PostIOilTankById, objId);
        if (Application.platform == RuntimePlatform.WebGLPlayer)
        {
            url = url.Substring(url.IndexOf("api") - 1);
        }
        HttpManager.Instance.Post(url, json, () =>
        {
            ShowBindList(NowType, NowClickObject);
        });
    }

    public void SaveDeviceObjConfig()
    {
        var json = JsonConvert.SerializeObject(BindObjectList);
        string url = string.Format(HttpManager.Instance.PostIOilTankById, objId);
        if (Application.platform == RuntimePlatform.WebGLPlayer)
        {
            url = url.Substring(url.IndexOf("api") - 1);
        }
        HttpManager.Instance.Post(url, json, () =>
        {
            Debug.Log("保存成功!");
        });
    }
}