using System;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiCommon.Filters;
using Siger.ApiCommon.Result;
using Siger.ApiCommon.Utilities;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.AppSettings;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Log;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Data;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Repository.Extensions;
using Siger.Middlelayer.Repository.Repositories.Interface;

namespace Siger.ApiConfig.Controller
{
    public class ClientVersionController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly ISigerClientVersion _sigerClient;
        public ClientVersionController(IUnitOfWork unitOfWork, ISigerClientVersion sigerClient)
        {
            _unitOfWork = unitOfWork;
            _sigerClient = sigerClient;
        }

        [HttpGet]
        public IActionResult GetPagedList(string starttime, string endtime, string search, int client, int page, int pagesize)
        {
            Expression<Func<siger_client_version, bool>> funkey = f => f.status == (int)RowState.Valid;
            Expression<Func<siger_client_version, bool>> funsearch = f => true;
            Expression<Func<siger_client_version, bool>> funclient = f => true;
            Expression<Func<siger_client_version, bool>> funtime = f => true;

            if (!string.IsNullOrEmpty(search))
            {
                funsearch = f => f.name.Contains(search) || f.version.Contains(search) || f.url.Contains(search);
            }
            if (client > 0)
            {
                funclient = f => f.client == client;
            }

            if (!string.IsNullOrEmpty(starttime) && !string.IsNullOrEmpty(endtime))
            {
                funtime = f => (f.createtime <= endtime.ToDateTime() && f.createtime >= starttime.ToDateTime());
            }

            var predicate = funkey.And(funsearch).And(funclient).And(funtime);
            var data = _sigerClient.GetPagedList(page, pagesize, predicate, "createtime");
            return new PagedObjectResult(data.Data, data.Total, page, pagesize);
        }

        [HttpPost]
        public IActionResult UploadFile(ClientType client)
        {
            if (client <= 0)
            {
                throw new BadRequestException(RequestEnum.InputValueError);
            }

            var files = Request.Form.Files;
            if (files == null)
            {
                throw new BadRequestException(RequestEnum.ParameterError);
            }

            var file = files[0];
            if (!IsExeFile(file.FileName))
            {
                throw new BadRequestException(RequestEnum.InputValueError);
            }
            var fileSetting = Config<FileSettings>.Get();
            if (fileSetting == null)
            {
                throw new BadRequestException(CommonEnum.GetCommCfgFailed);
            }
            string rootDir;
            string fileDir;
            switch (client)
            {
                case ClientType.Lamp:
                    rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, "InstallPackage", "Lamp");
                    
                    fileDir = "/InstallPackage/Lamp/";
                    break;
                case ClientType.TlmStorage:
                    rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder,"InstallPackage", "Tlm");
                    rootDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileSetting.FileSetting.PhysicalFolder, "InstallPackage", "Tlm");
                    fileDir = "/InstallPackage/Tlm/";
                    break;
                default:
                    throw new BadRequestException(CommonEnum.Fail);
            }
            

            //save file
            var temporaryFileName = file.FileName;
            var fileName = Path.Combine(rootDir, temporaryFileName);
            fileDir += temporaryFileName;
            try
            {
                using (var stream = new FileStream(fileName, FileMode.Create))
                {
                    file.CopyTo(stream);
                }

                if (!System.IO.File.Exists(fileName))
                {
                    throw new BadRequestException(RequestEnum.ImportFailed);
                }
                return new ObjectResult(fileDir);
            }
            catch (Exception e)
            {
                Logger.WriteLineError($"import {client} failed, error:" + e.Message);
                throw new BadRequestException(RequestEnum.ImportFailed);
            }
        }

        private static bool IsExeFile(string fileName)
        {
            fileName = fileName.ToLower();
            if (fileName.EndsWith(".exe"))
            {
                return true;
            }

            return false;
        }

        [HttpGet]
        [NoTokenValidateFilter]
        public IActionResult GetNewVersion(int client)
        {
            if (client <= 0)
            {
                throw new BadRequestException(RequestEnum.ParameterError);
            }
            var clients = _sigerClient.GetList(t => t.client == client && t.status == (int)RowState.Valid).ToList();
            if (clients.Any())
            {
                var version = clients.FirstOrDefault();
                foreach (var ver in clients)
                {
                    var isNew = version != null && CheckVersionIsNew(version.version, ver.version);
                    version = isNew ? ver : version;
                }
                return new ObjectResult(version);
            }
            throw new BadRequestException(CommonEnum.Fail);
        }

        private bool CheckVersionIsNew(string currentVersion, string newVersion)
        {
            var cvers = currentVersion.Split('.');
            var nvers = newVersion.Split('.');
            if (cvers.Length != 4 || nvers.Length != 4)
            {
                return false;
            }
            for (var i = 0; i < 4; i++)
            {
                int.TryParse(cvers[i], out var cver);
                int.TryParse(nvers[i], out var nver);
                if (cver > nver)
                {
                    return false;
                }
                if (cver < nver)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet]
        [NoTokenValidateFilter]
        [NoResultFilter]
        public IActionResult DownloadFile(int id)
        {
            var his = _sigerClient.Get(q => q.id == id && q.status == (int)RowState.Valid);
            if (his == null)
            {
                return new NoContentResult();
            }
            if (string.IsNullOrWhiteSpace(his.url))
            {
                return new NoContentResult();
            }
            var fileSetting = Config<FileSettings>.Get();
            if (fileSetting == null)
            {
                return new NoContentResult();
            }
            var rootDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileSetting.FileSetting.PhysicalFolder);
            if (!Directory.Exists(rootDir))
            {
                return new NoContentResult();
            }

            var path = rootDir + his.url;
            if (!System.IO.File.Exists(path))
            {
                return new NoContentResult();
            }
            try
            {
                var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
                var response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(stream) };
                response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                {
                    FileName = string.IsNullOrWhiteSpace(his.name) ? "" : his.name
                };

                return File(stream, "application/octet-stream");
            }
            catch
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        [HttpPost]
        public IActionResult Add([FromBody]AddClientVersion req)
        {
            if (string.IsNullOrEmpty(req.version) || string.IsNullOrEmpty(req.url) || req.client <= 0)
            {
                throw new BadRequestException(RequestEnum.InputValueError);
            }

            var versions = _sigerClient.Get(t => t.version == req.version && t.status == (int) RowState.Valid);
            if (versions != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }

            var model = new siger_client_version
            {
                url = req.url,
                version = req.version,
                client = req.client,
                programname = GetProgramName(req.client),
                desc = req.desc ?? "",
                name = req.name,
                createtime = DateTime.Now,
                updatetime = DateTime.Now
            };
            _sigerClient.Insert(model);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }

            throw new BadRequestException(CommonEnum.Fail);
        }

        private string GetProgramName(int client)
        {
            switch (client)
            {
                case (int)ClientType.Lamp:
                    return "SigerData.LampClient";
                case (int)ClientType.TlmStorage:
                    return "Siger.Middlelayer.TLM.StorageClient";
                default:
                    throw new BadRequestException(RequestEnum.InputValueError);
            }
        }

        [HttpPost]
        public IActionResult Modify([FromBody]UpdateClientVersion req)
        {
            var entity = _sigerClient.Get(t => t.id == req.id && t.status == (int) RowState.Valid);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.Fail);
            }

            if (string.IsNullOrEmpty(req.version) || string.IsNullOrEmpty(req.url) || req.client <= 0)
            {
                throw new BadRequestException(RequestEnum.InputValueError);
            }

            var versions = _sigerClient.Get(t => t.version == req.version && t.status == (int)RowState.Valid && t.id != req.id);
            if (versions != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }

            entity.url = req.url;
            entity.url = req.url;
            entity.version = req.version;
            entity.client = req.client;
            entity.programname = GetProgramName(req.client);
            entity.desc = req.desc ?? "";
            entity.name = req.name;
            entity.updatetime = DateTime.Now;
            _sigerClient.Update(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }

            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpGet]
        public IActionResult Delete(int id)
        {
            var entity = _sigerClient.Get(t => t.id == id && t.status == (int)RowState.Valid);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.NoData);
            }

            entity.status = (int) RowState.Invalid;
            _sigerClient.Update(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }

            throw new BadRequestException(CommonEnum.Fail);
        }
    }
}