using BPASmartClient.Helper;
using BPASmartDatavDeviceClient.IoT;
using DataVAPI.Tool.IOT;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPASmartClient.IoT.Model
{
    /// <summary>
    /// 阿里云文件上传
    /// </summary>
    public class FileUpload
    {
        public static Dictionary<string, string> UploadData = new Dictionary<string, string>();
        public static string FileName = $"HBL.LogDir{DateTime.Now.ToString("yyyy_M_d")}";
        public static string path = $"{System.AppDomain.CurrentDomain.BaseDirectory}LogDir\\{FileName}.log";
        public static void SetUploadData(string key, string value)
        {
            UploadData[key] = value;
        }
        public static string GetUploadData(string key)
        {
            return UploadData.ContainsKey(key) ? UploadData[key] : string.Empty;
        }
        public static long length = 0;
        public static byte[] FileBlock;
        /// <summary>
        /// 文件请求上传
        /// </summary>
        public static void FileRequest(DataVReport dataV)
        {
            FileBlock = FileContent(path);
            length = FileBlock.Count();
            FileUploadModel fileUpload = new FileUploadModel();
            fileUpload.@params.fileName = FileName;
            fileUpload.@params.fileSize = length;
            fileUpload.@params.conflictStrategy = "overwrite";//覆盖模式
            //fileUpload.@params.ficMode = "crc64";
            //fileUpload.@params.ficValue = CRC.ToCRC16(FileBlock);
            fileUpload.@params.initUid = $"ab{RandomHelper.GenerateRandomCode()}";

            //上传到阿里云物联网平台的OSS存储空间中
            fileUpload.@params.extraParams.ossOwnerType = "iot-platform";

            //表示上传到设备所属用户自己的OSS存储空间中
            //{ossbucket}/aliyun-iot-device-file/${instanceId}/${productKey}/${serviceId}/${deviceName}/${fileName}
            //fileUpload.@params.extraParams.ossOwnerType = "device-user";
            //fileUpload.@params.extraParams.serviceId = "black";
            //fileUpload.@params.extraParams.fileTag = new Dictionary<string, string> { {"Time", DateTime.Now.ToString("yyyy_M_d") },{"Name", "HBL.LogDir" } };

            dataV.IOT_Publish(dataV.FileUpLoadTopic, Tools.JsonConvertTools(fileUpload));
        }

        /// <summary>
        /// 文件上传
        /// </summary>
        public static void FileSend(DataVReport dataV, string uploadId)
        {
            FileSendModel fileSend = new FileSendModel();
            fileSend.@params.uploadId = uploadId;
            fileSend.@params.offset = 0;
            fileSend.@params.bSize = length;
            //结构如下图
            //Header.length(高 低) + Header(字节数组UTF-8) + 文件分片的字节数组 + "分片校验值CrC16 低 高" 
            byte[] Header = Encoding.UTF8.GetBytes(Tools.JsonConvertTools(fileSend));
            byte HeaderLen_L = (byte)(Header.Length);
            byte HeaderLen_H = (byte)(Header.Length >> 8);
            byte[] CRC16 = CRC16Standard.getCRCBytes(FileBlock);//CRC.CRC16(FileBlock);
            List<byte> message = new List<byte>() { HeaderLen_H, HeaderLen_L };
            message.AddRange(Header);
            message.AddRange(FileBlock);
            message.AddRange(CRC16);
            dataV.IOT_Publish(dataV.FileUpLoadSendTopic, message.ToArray());
        }

        /// <summary>
        /// 取消文件上传
        /// </summary>
        public static void FileCancelSend(DataVReport dataV, string uploadId)
        {
            CancelSend cancel = new CancelSend(uploadId);
            dataV.IOT_Publish(dataV.CancelFileUpLoadSendTopic, Tools.JsonConvertTools(cancel));
        }


        /// <summary>
        /// 读取文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private static byte[] FileContent(string fileName)
        {
            using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                try
                {
                    byte[] buffur = new byte[fs.Length];
                    fs.Read(buffur, 0, (int)fs.Length);
                    return buffur;
                }
                catch (Exception ex)
                {
                    return new byte[0];
                }
            }
        }
        /// <summary>
        /// 读取文件字节
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static byte[] ReadFile(string path)
        {
            //创建d:\file.txt的FileStream对象
            FileStream fstream = new FileStream($@"{path}", FileMode.OpenOrCreate);
            byte[] bData = new byte[fstream.Length];
            //设置流当前位置为文件开始位置
            fstream.Seek(0, SeekOrigin.Begin);

            //将文件的内容存到字节数组中（缓存）
            fstream.Read(bData, 0, bData.Length);
            string result = Encoding.UTF8.GetString(bData);
            Console.WriteLine(result);
            if (fstream != null)
            {
                //清除此流的缓冲区，使得所有缓冲的数据都写入到文件中
                fstream.Flush();
                fstream.Close();
            }
            return bData;
        }
    }

    #region 请求上传文件
    /// <summary>
    /// 请求上传文件
    /// </summary>
    public class FileUploadModel
    {
        /// <summary>
        /// 消息ID号
        /// 0~4294967295
        /// </summary>
        public string id { get; set; }
        /// <summary>
        /// 请求业务参数
        /// </summary>
        public BusinessParameters @params { get; set; }

        public FileUploadModel()
        {
            id = RandomHelper.GenerateRandomCode();
            @params = new BusinessParameters();
        }
    }

    /// <summary>
    /// 业务参数
    /// </summary>
    public class BusinessParameters
    {
        /// <summary>
        /// 设备上传文件的名称
        /// </summary>
        public string fileName { get; set; }
        /// <summary>
        /// 上传文件大小，单位字节。单个文件大小不超过16 MB。
        /// 取值为-1时，表示文件大小未知。文件上传完成时，需在上传文件分片的消息中，指定参数isComplete
        /// </summary>
        public long fileSize { get; set; }
        /// <summary>
        /// 物联网平台对设备上传同名文件的处理策略,默认为overwrite
        /// overwrite：覆盖模式 append：文件追加模式 reject：拒绝模式
        /// </summary>
        public string conflictStrategy { get; set; } = "overwrite";
        /// <summary>
        /// 文件的完整性校验模式，目前可取值crc64 
        /// 若不传入，在文件上传完成后不校验文件完整性
        /// </summary>
        public string ficMode { get; set; }
        /// <summary>
        /// 文件的完整性校验值，是16位的Hex格式编码的字符串
        /// </summary>
        public string ficValue { get; set; }
        /// <summary>
        /// 自定义的设备请求上传文件的任务唯一ID，同一上传任务请求必须对应相同的唯一ID
        /// 不传入：物联网平台的云端识别当前请求为新的文件上传请求
        /// </summary>
        public string initUid { get; set; }
        /// <summary>
        /// 设备上传文件至OSS存储空间的配置参数
        /// </summary>
        public ConfigureParameters extraParams { get; set; } = new ConfigureParameters();
    }
    /// <summary>
    /// 配置参数
    /// </summary>
    public class ConfigureParameters
    {
        /// <summary>
        /// 设备上传文件的目标OSS所有者类型
        /// iot-platform：表示上传到阿里云物联网平台的OSS存储空间中
        /// device-user：表示上传到设备所属用户自己的OSS存储空间中
        /// </summary>
        public string ossOwnerType { get; set; } = "device-user";
        /// <summary>
        /// 文件上传相关的业务ID
        /// </summary>
        public string serviceId { get; set; }
        /// <summary>
        /// 标签
        /// </summary>
        public Dictionary<string, string> fileTag { get; set; }
        public ConfigureParameters()
        {

        }
    }
    #endregion

    #region 请求上传文件响应
    /// <summary>
    /// 请求响应
    /// </summary>
    public class FileUploadModelResult
    {
        /// <summary>
        /// 消息ID号
        /// 0~4294967295
        /// </summary>
        public string id { get; set; }
        /// <summary>
        /// 结果码。返回200表示成功
        /// </summary>
        public int code { get; set; }
        /// <summary>
        /// 请求失败时，返回的错误信息
        /// </summary>
        public string message { get; set; }
        /// <summary>
        /// 返回设备端的数据。
        /// </summary>
        public ResultData data { get; set; }

    }
    /// <summary>
    /// 请求响应数据
    /// </summary>
    public class ResultData
    {
        /// <summary>
        /// 设备上传文件的名称
        /// </summary>
        public string fileName { get; set; }
        /// <summary>
        /// 本次上传文件任务的标识ID。后续上传文件分片时，需要传递该文件标识ID。
        /// </summary>
        public string uploadId { get; set; }
        /// <summary>
        /// 仅当请求参数conflictStrategy为append，且物联网平台云端存在未完成上传的文件时，返回的已上传文件的大小，单位为字节。
        /// </summary>
        public long offset { get; set; }
        /// <summary>
        /// 当前上传文件分片的大小
        /// </summary>
        public long bSize { get; set; }
        /// <summary>
        /// 当上传了最后一个分片数据后，文件上传完成
        /// </summary>
        public bool complete { get; set; }
        /// <summary>
        /// 文件的完整性校验模式。若请求上传文件时传入了该参数，对应的值仅支持为crc64
        /// </summary>
        public string ficMode { get; set; }
        /// <summary>
        /// 文件上传完成，返回设备请求上传文件时的
        /// </summary>
        public string ficValueClient { get; set; }
        /// <summary>
        /// 文件上传完成，返回物联网平台云端计算的文件完整性校验值。该值与ficValueClient值相同，表示文件上传完整。
        /// </summary>
        public string ficValueServer { get; set; }
    }
    #endregion

    #region 上传文件
    public class FileSendModel
    {
        /// <summary>
        /// 消息ID号
        /// 0~4294967295
        /// </summary>
        public string id { get; set; }
        /// <summary>
        /// 上传业务参数
        /// </summary>
        public SendBusinessParameters @params { get; set; } = new SendBusinessParameters();
        public FileSendModel()
        {
            id = RandomHelper.GenerateRandomCode();
        }
    }
    /// <summary>
    /// 上传业务参数
    /// </summary>
    public class SendBusinessParameters
    {
        /// <summary>
        /// 设备请求上传文件时返回的文件上传任务标识ID。
        /// </summary>
        public string uploadId { get; set; }
        /// <summary>
        /// 已上传文件分片的总大小，单位为字节。
        /// </summary>
        public long offset { get; set; }
        /// <summary>
        /// 当前上传文件分片的大小，单位为字节
        /// </summary>
        public long bSize { get; set; }
        /// <summary>
        /// 仅当设备请求上传文件中fileSize为-1，即文件大小未知时，该参数有效，表示当前分片是否是文件的最后一个分片
        /// </summary>
        public bool isComplete { get; set; } = true;
    }
    #endregion

    #region 取消文件上传
    /// <summary>
    /// 取消上传
    /// </summary>
    public class CancelSend
    {
        /// <summary>
        /// 消息ID号
        /// 0~4294967295
        /// </summary>
        public string id { get; set; }
        /// <summary>
        /// 请求业务参数
        /// </summary>
        public object @params { get; set; }

        public CancelSend(string uploadId)
        {
            id = RandomHelper.GenerateRandomCode();
            @params = new { uploadId = uploadId };
        }
    }
    #endregion

    public class RandomHelper
    {
        /// <summary>
        ///生成制定位数的随机码（数字）
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string GenerateRandomCode(int length = 10)
        {
            var result = new StringBuilder();
            for (var i = 0; i < length; i++)
            {
                var r = new Random(Guid.NewGuid().GetHashCode());
                result.Append(r.Next(0, 10));
            }
            return result.ToString();
        }
    }
}
