using DocumentFormat.OpenXml.Bibliography;
using DocumentFormat.OpenXml.Office2016.Excel;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Wordprocessing;
using Infrastructure;
using Infrastructure.Utils;
using NetTopologySuite;
using NetTopologySuite.Features;
using NetTopologySuite.Geometries;
using NetTopologySuite.IO;
using Newtonsoft.Json.Linq;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using OpenAuth.App.Base.Tree;
using OpenAuth.App.BaseApp.Base;
using OpenAuth.App.FormModule;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.ServiceApp.DataMaintenance.Request;
using OpenAuth.Repository;
using OpenAuth.Repository.Core;
using OpenAuth.Repository.Domain.DataMaintenance;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Ocsp;
using SqlSugar;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using System.IO.Compression;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;
using Yitter.IdGenerator;
using static NPOI.HSSF.UserModel.HeaderFooter;

namespace OpenAuth.App.ServiceApp.DataMaintenance
{
    /// <summary>
    /// 应用管理
    /// </summary>
    public class ApplicationManagementApp : SqlSugarBaseApp<ApplicationData, SugarDbContext>
    {
        public ApplicationManagementApp(ISugarUnitOfWork<SugarDbContext> unitWork,
        ISimpleClient<ApplicationData> repository, IAuth auth) : base(unitWork,
        repository,
        auth)
        {
            _auth = auth;
        }
        /// <summary>
        /// 获取应用列表
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public async Task<Response<List<ApplicationData>>> GetApplicationList(string name, int isCatalogue)
        {
            using (var db = UnitWork.CreateContext())
            {
                var user = _auth.GetCurrentUser().User;
                var result = new Response<List<ApplicationData>>();

                // 使用参数化
                var level = await db.Db.Ado.GetIntAsync("select min(\"Level\") from sys_userorg where \"UserId\" = @userId",
                    new { userId = user.Id });

                // 构建基础查询
                var baseQuery = db.ApplicationData.AsQueryable();

                // 根据用户级别过滤数据
                if (level > 0)
                {
                    var orgs = await db.SysUserOrg.AsQueryable()
                        .Where(a => a.UserId == user.Id)
                        .Select(a => a.OrgId)
                        .ToListAsync();

                    var userIds = await db.SysUserOrg.AsQueryable()
                        .Where(a => orgs.Contains(a.OrgId))
                        .Select(a => a.UserId)
                        .ToListAsync();
                    baseQuery = baseQuery.Where(r => userIds.Contains(r.CreateUserId));
                }

                // 应用名称过滤
                if (!string.IsNullOrEmpty(name))
                {
                    baseQuery = baseQuery.Where(a => a.ApplicationName.Contains(name));
                }
                //服务过滤
                if (isCatalogue != 0)
                {
                    baseQuery = baseQuery.Where(a => a.IsServer == 0);
                }

                // 执行查询并构建树形结构
                var query = await baseQuery.Select<ApplicationData>().ToListAsync();
                result.Result = UtilMethods.BuildTree(db.Db, query, "Id", "Pid", "Child", 0).ToList();
                return result;
            }
        }
        //添加应用
        public async Task<Response<bool>> Add(ApplicationData app)
        {
            using (var db = UnitWork.CreateContext())
            {
                app.Id = YitIdHelper.NextId();
                app.CreateUserId = _auth.GetCurrentUser().User.Id;
                app.CreateTime = DateTime.Now;
                if (await db.ApplicationData.AsInsertable(app).ExecuteCommandAsync() > 0)
                {
                    if (app.IsServer == 1)
                    {
                        //先插入一条数据
                        var geography = NtsGeometryServices.Instance.CreateGeometryFactory(4326);
                        var point = geography.CreatePoint(new Coordinate(0, 0));
                        await db.Db.InsertableByDynamic(new { Id = 0, geom = point.AsText() }).AS(app.TableName).ExecuteCommandAsync();
                        var response = await GeoUtil.CreateStoreAndLayer("", "EPSG:4326", app.TableName, "");
                        if (response)
                        {
                            //删除数据 
                            await db.Db.Deleteable<object>().AS(app.TableName).Where("\"Id\"=@Id", new { Id = 0 }).ExecuteCommandAsync();
                        }
                    }
                    if (db.Commit())
                    {
                        return new Response<bool> { Result = true };
                    }
                    else
                    {
                        return new Response<bool> { Result = false, Message = "添加失败" };
                    }
                    
                }
                else
                    return new Response<bool> { Result = false, Message = "添加失败" };
            }

        }


        //编辑应用
        public async Task<Response<bool>> Update(ApplicationData app)
        {
            if (await Repository.AsUpdateable(app).UpdateColumns(r => new ApplicationData
            {
                ApplicationName = app.ApplicationName,
                ServerId = app.ServerId,
                ServerName = app.ServerName,
                Sort = app.Sort,
                Pid = app.Pid,
                TableName = app.TableName,
                IsServer = app.IsServer,
                ServerType = app.ServerType,
            }).ExecuteCommandAsync() > 0)
                return new Response<bool> { Result = true };
            else
                return new Response<bool> { Result = false, Message = "编辑失败" };
        }
        //删除应用
        public async Task<Response<bool>> Delete(long id)
        {
            if (await Repository.AsDeleteable().Where(a => a.Id == id).ExecuteCommandAsync() > 0)
                return new Response<bool> { Result = true };
            else
                return new Response<bool> { Result = false, Message = "删除失败" };
        }
        //获取应用详情
        public async Task<Response<ApplicationData>> Get(long id)
        {
            var result = new Response<ApplicationData>();
            result.Result = await Repository.AsQueryable().FirstAsync(a => a.Id == id);
            return result;
        }
        //获取应用列表
        public async Task<Response<PageInfo<List<ApplicationData>>>> GetList(PageReq req)
        {
            var result = new Response<PageInfo<List<ApplicationData>>>();
            var totalCount = 0;
            var objs = Repository.AsQueryable();
            objs.WhereIF(!string.IsNullOrEmpty(req.key), u => u.ApplicationName.Contains(req.key));
            var data = await objs.OrderByDescending(u => u.CreateTime).ToPageListAsync(req.page, req.limit, totalCount);
            result.Result = new PageInfo<List<ApplicationData>>
            {
                Items = data,
                Total = totalCount
            };
            return result;
        }
        //获取数据库表名及注释
        public async Task<Response<DataTable>> GetGeomTableList(PageReq req)
        {
            using (var db = UnitWork.CreateContext())
            {
                var query = await db.Db.Ado.GetDataTableAsync(@"
                      SELECT t.""table_name"",  pg_catalog.obj_description(c.oid) AS table_comment
                       FROM  information_schema.tables t JOIN  pg_catalog.pg_class c ON c.relname = t.""table_name""
                       WHERE  t.table_schema = 'public'  AND EXISTS ( SELECT 1
                       FROM information_schema.columns col
                       WHERE col.""table_name"" = t.""table_name""
                       AND col.table_schema = t.table_schema
                       AND col.data_type = 'USER-DEFINED'  
                       AND col.udt_name = 'geometry');");

                return new Response<DataTable>()
                {
                    Result = query,
                };
            }
        }
        //查询一张表里的所有数据
        public async Task<Response<PageInfo<List<object>>>> GetDataList(TableDataReq tableDataReq)
        {
            using (var db = UnitWork.CreateContext())
            {
                StringBuilder stringBuilder = new StringBuilder();
                RefAsync<int> totalNumber = 0;
                var query = db.Db.Queryable<object>().AS(tableDataReq.TableName);
                List<string> fieldType = new List<string>
                {
                     "smallint",
                     "integer",
                     "bigint",
                     "real",
                     "double precision",
                     "numeric",
                     "money",
                     "char",
                 };
                foreach (var filter in tableDataReq.Filter)
                {
                    // 判断字段类型
                    if (fieldType.Contains(filter.Type))
                    {
                        query.Where(BuildIntCondition(filter.Field, filter.Operator, filter.Value));
                    }
                    else
                    {
                        query.Where(BuildStringCondition(filter.Field, filter.Operator, filter.Value));
                    }
                }
                var fields = string.Join(",", tableDataReq.Field.Select(f => $"\"{f}\""));
                var dataList = await query.Select(fields).ToPageListAsync(tableDataReq.page, tableDataReq.limit, totalNumber);
                return new Response<PageInfo<List<dynamic>>>
                {
                    Result = new PageInfo<List<dynamic>> { Items = dataList, Total = totalNumber }
                };
            }
        }
        //拼接int类型的条件
        private static string BuildIntCondition(string column, string operators, string value)
        {
            if (operators == "大于")
            {
                return $"\"{column}\" > {value}";
            }
            else if (operators == "小于")
            {
                return $"\"{column}\" < {value}";
            }
            else if (operators == "大于等于")
            {
                return $"\"{column}\" > {value}";
            }
            else if (operators == "小于等于")
            {
                return $"\"{column}\" > {value}";
            }
            else if (operators == "介于")
            {
                var range = value.Split(',');
                if (int.TryParse(range[0], out int lower) && int.TryParse(range[1], out int upper))
                {
                    return $"\"{column}\" BETWEEN {lower} AND {upper}";
                }
                else
                {
                    throw new ArgumentException("无效的范围值");
                }
            }
            else
            {
                return $"\"{column}\" = {value}";
            }
        }
        //拼接string类型的条件
        private static string BuildStringCondition(string column, string operators, string value)
        {
            if (operators.StartsWith("包含"))
            {
                return $"\"{column}\" LIKE '%{value}%'";
            }
            else if (operators.StartsWith("不包含"))
            {
                return $"\"{column}\" NOT LIKE '%{value}%'";
            }
            else if (operators.StartsWith("以开头"))
            {
                return $"\"{column}\" LIKE '{value}%'";
            }
            else if (operators.StartsWith("以结尾"))
            {
                return $"\"{column}\" LIKE '%{value}'";
            }
            else
            {
                return $"\"{column}\" = '{value}'";
            }
        }

        #region 导出数据
        public List<dynamic> GetTableAndViewColumnList(string tableName)
        {
            using (var db = UnitWork.CreateContext())
            {
                string query = $@"
                             SELECT 
                                 c.column_name, 
                                 c.data_type,
                                 d.description
                             FROM 
                                 information_schema.columns c
                             LEFT JOIN 
                                 pg_catalog.pg_class t ON t.relname = c.table_name
                             LEFT JOIN 
                                 pg_catalog.pg_attribute a ON a.attnum > 0 
                                 AND a.attrelid = t.oid 
                                 AND a.attname = c.column_name
                             LEFT JOIN 
                                 pg_catalog.pg_namespace n ON n.oid = t.relnamespace
                             LEFT JOIN 
                                 pg_catalog.pg_description d ON d.objoid = a.attrelid 
                                 AND d.objsubid = a.attnum
                             WHERE 
                                 c.table_name = @tableName 
                                 AND c.table_schema = 'public';";
                // 执行查询并获取结果
                var viewColumns = db.Db.Ado.SqlQuery<dynamic>(query, new { tableName = tableName });
                return viewColumns;
            }
        }
        //查询所有数据
        public async Task<List<dynamic>> GetDataAllList(TableDataReq tableDataReq)
        {
            using (var db = UnitWork.CreateContext())
            {
                StringBuilder stringBuilder = new StringBuilder();
                var query = db.Db.Queryable<object>().AS(tableDataReq.TableName);
                List<string> fieldType = new List<string>
                {
                     "smallint",
                     "integer",
                     "bigint",
                     "real",
                     "double precision",
                     "numeric",
                     "money",
                     "char",
                 };
                foreach (var filter in tableDataReq.Filter)
                {
                    // 判断字段类型
                    if (fieldType.Contains(filter.Type))
                    {
                        query.Where(BuildIntCondition(filter.Field, filter.Operator, filter.Value));
                    }
                    else
                    {
                        query.Where(BuildStringCondition(filter.Field, filter.Operator, filter.Value));
                    }
                }
                var fields = string.Join(",", tableDataReq.Field.Select(f => $"\"{f}\""));
                var dataList = await query.Select<dynamic>(fields).ToListAsync();
                return dataList;
            }
        }
        //导出Excel
        public async Task<Response<MemoryStream>> ListToExcel(TableDataReq tableDataReq, List<ModuleColumn> headers)
        {
            Response<MemoryStream> response = new Response<MemoryStream>();
            try
            {
                var list = await GetDataAllList(tableDataReq);
                HSSFWorkbook workbook = new HSSFWorkbook();
                #region 内容样式

                IFont font1 = workbook.CreateFont(); //创建一个字体样式对象
                font1.FontName = "Microsoft YaHei"; //和excel里面的字体对应
                //font1.Boldweight = short.MaxValue;//字体加粗
                font1.FontHeightInPoints = 12; //字体大小
                ICellStyle style = workbook.CreateCellStyle(); //创建样式对象
                style.BorderBottom = BorderStyle.Thin;
                style.BorderLeft = BorderStyle.Thin;
                style.BorderRight = BorderStyle.Thin;
                style.BorderTop = BorderStyle.Thin;
                style.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
                style.VerticalAlignment = VerticalAlignment.Center;
                style.SetFont(font1); //将字体样式赋给样式对象 
                style.WrapText = true;

                #endregion

                #region 标题样式

                IFont font = workbook.CreateFont(); //创建一个字体样式对象
                font.FontName = "Microsoft YaHei"; //和excel里面的字体对应
                font.Boldweight = (short)FontBoldWeight.Bold; //字体加粗
                font.FontHeightInPoints = 12; //字体大小
                ICellStyle style1 = workbook.CreateCellStyle(); //创建样式对象
                style1.BorderBottom = BorderStyle.Thin;
                style1.BorderLeft = BorderStyle.Thin;
                style1.BorderRight = BorderStyle.Thin;
                style1.BorderTop = BorderStyle.Thin;
                style1.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
                style1.VerticalAlignment = VerticalAlignment.Center;
                style1.SetFont(font); //将字体样式赋给样式对象 

                #endregion

                #region 创建表头
                int m = list.Count / 60000 + 1;
                for (int k = 0; k < m; k++)
                {
                    ISheet sheet = workbook.CreateSheet("Sheet" + k.ToString());
                    IRow rowHeader = sheet.CreateRow(0);
                    rowHeader.Height = 20 * 30;
                    for (int i = 0; i < tableDataReq.Field.Count; i++)
                    {
                        rowHeader.CreateCell(i);
                        rowHeader.Cells[i].CellStyle = style1;
                        var va = headers.Where(r => r.key == tableDataReq.Field[i].ToString()).FirstOrDefault().value;
                        rowHeader.Cells[i].SetCellValue(va);
                        sheet.SetColumnWidth(i, 20 * 350);
                    }
                    #endregion

                    #region 填充数据
                    var val = (k + 1) * 60000;
                    var num = 60000;
                    if (val > list.Count())
                    {
                        num = list.Count - k * 60000;
                    }
                    for (int i = 0; i < num; i++) //循环数据
                    {
                        var item = list[k * 60000 + i];     //获取数据
                        IRow dataRow = sheet.CreateRow(i + 1);  //创建行
                        for (int j = 0; j < tableDataReq.Field.Count; j++) //循环表头
                        {
                            //数据处理
                            var objValue = "";
                            var fieldKey = tableDataReq.Field[j].ToString();
                            if (item is ExpandoObject expandoItem)
                            {
                                var dictItem = (IDictionary<string, object>)expandoItem;
                                if (dictItem.ContainsKey(fieldKey))
                                {
                                    objValue = dictItem[fieldKey]?.ToString();
                                }
                            }
                            //创建单元格
                            dataRow.CreateCell(j);
                            dataRow.Cells[j].CellStyle = style;  //添加单元格样式
                            if (objValue != null && !string.IsNullOrEmpty(objValue.ToString()))
                            {
                                dataRow.Cells[j].SetCellValue(objValue.ToString()); //填充Excel单元格
                            }
                            else
                            {
                                dataRow.Cells[j].SetCellValue(""); //填充Excel单元格
                            }
                        }
                    }
                }

                #endregion

                response.Result = new MemoryStream();
                workbook.Write(response.Result);
                workbook = null;
                response.Result.Close();
                response.Result.Dispose();
                response.Code = 200;
                response.Message = "获取成功";
            }
            catch (Exception ex)
            {
                response.Code = 500;
                response.Message = ex.Message;
            }
            return response;
        }


        /// <summary>
        /// 导出shp文件
        /// </summary>
        /// <param name="req"></param>
        /// <param name="shpFilePath"></param>
        /// <param name="shpFilePathzip"></param>
        /// <exception cref="Exception"></exception>
        public async Task ExportShapefile(TableDataReq tableDataReq, string shpFilePath, string shpFilePathzip, List<ModuleColumn> headers)
        {
            var data = await GetDataAllList(tableDataReq);
            if (data == null || data.Count == 0)
            {
                throw new Exception("暂无数据");
            }

            List<IFeature> features = new List<IFeature>();

            foreach (var row in data)
            {
                var geometry = ParseGeometry(row.geom.ToString());
                if (geometry == null)
                {
                    throw new Exception("数据不可用");
                }
                AttributesTable attributes = new AttributesTable();
                IFeature feature = null;
                for (int i = 0; i < tableDataReq.Field.Count; i++)
                {
                    var va = headers.Where(r => r.key == tableDataReq.Field[i].ToString()).FirstOrDefault().value;

                    // 访问动态属性
                    var fieldName = tableDataReq.Field[i].ToString();
                    //var fieldValue = row.GetType().GetProperty(fieldName)?.GetValue(row, null);

                    if (row is ExpandoObject expandoItem)
                    {
                        var dictItem = (IDictionary<string, object>)expandoItem;
                        if (dictItem.ContainsKey(fieldName))
                        {
                            attributes.Add(va, dictItem[fieldName] == null ? "" : dictItem[fieldName].ToString());
                        }
                    }
                }
                feature = new Feature(geometry, attributes);
                features.Add(feature);

            }

            if (features.Count == 0)
            {
                throw new Exception("数据不可用");
            }

            // 导出 SHP 文件及其关联文件 
            ExportToShapefileFour(shpFilePath, features);
            // 将文件打包成 ZIP
            CreateZipFromShapefiles(shpFilePath, shpFilePathzip);
        }
        public Geometry ParseGeometry(string wkt)
        {
            if (string.IsNullOrEmpty(wkt))
            {
                return null;
            }

            var reader = new WKTReader();
            return reader.Read(wkt);
        }
        public void ExportToShapefileFour(string shpPath, List<IFeature> features)
        {
            string prjStr =
            @"GEOGCS[""GCS_China_Geodetic_Coordinate_System_2000"",DATUM[""D_China_2000"",SPHEROID[""CGCS2000"",6378137.0,298.257222101]],PRIMEM[""Greenwich"",0.0],UNIT[""Degree"",0.0174532925199433]]";
            var cpgPath = System.IO.Path.ChangeExtension(shpPath, "prj");
            System.IO.File.WriteAllText(cpgPath, prjStr, Encoding.UTF8);

            NetTopologySuite.IO.Esri.Shapefile.WriteAllFeatures(features, shpPath, encoding: Encoding.UTF8);
        }
        public void CreateZipFromShapefiles(string shpPath, string zipPath)
        {
            var files = new List<string>
        {
            System.IO.Path.ChangeExtension(shpPath, "cpg"),
            shpPath,
            System.IO.Path.ChangeExtension(shpPath, "shx"),
            System.IO.Path.ChangeExtension(shpPath, "dbf"),
            System.IO.Path.ChangeExtension(shpPath, "prj")
        };

            using (var zipArchive = ZipFile.Open(zipPath, ZipArchiveMode.Create))
            {
                foreach (var file in files)
                {
                    if (System.IO.File.Exists(file))
                    {
                        zipArchive.CreateEntryFromFile(file, System.IO.Path.GetFileName(file));
                    }
                }
            }
        }
        #endregion

        //批量修改
        public async Task<Response<bool>> UpdateBatch(UpdateBatchDataReq updateBatchDataReq)
        {
            var result = new Response<bool>();
            using (var db = UnitWork.CreateContext())
            {
                if (updateBatchDataReq.OldValue == "")
                {
                    if (updateBatchDataReq.Ids != null && updateBatchDataReq.Ids.Count > 0)
                    {
                        var flag = await db.Db.Updateable<object>()
                            .AS(updateBatchDataReq.TableName)
                            .SetColumns(updateBatchDataReq.SingleField, updateBatchDataReq.NewValue)
                            .Where($"\"{updateBatchDataReq.SingleField}\" = @OldValue OR \"{updateBatchDataReq.SingleField}\" IS NULL", new { OldValue = updateBatchDataReq.OldValue })
                            .Where($"\"Id\" IN ({string.Join(",", updateBatchDataReq.Ids)})")
                            .ExecuteCommandAsync();
                    }
                    else
                    {
                        var flag = await db.Db.Updateable<object>()
                            .AS(updateBatchDataReq.TableName)
                            .SetColumns(updateBatchDataReq.SingleField, updateBatchDataReq.NewValue)
                            .Where($"\"{updateBatchDataReq.SingleField}\" = @OldValue OR \"{updateBatchDataReq.SingleField}\" IS NULL", new { OldValue = updateBatchDataReq.OldValue })
                            .ExecuteCommandAsync();
                    }


                }
                else
                {
                    if (updateBatchDataReq.Ids != null && updateBatchDataReq.Ids.Count > 0)
                    {
                        var flag = await db.Db.Updateable<object>()
                            .AS(updateBatchDataReq.TableName)
                            .SetColumns(updateBatchDataReq.SingleField, updateBatchDataReq.NewValue)
                            .Where($"\"{updateBatchDataReq.SingleField}\" = @OldValue", new { OldValue = updateBatchDataReq.OldValue })
                            .Where($"\"Id\" IN ({string.Join(",", updateBatchDataReq.Ids)})")
                            .ExecuteCommandAsync();
                    }
                    else
                    {
                        var flag = await db.Db.Updateable<object>()
                            .AS(updateBatchDataReq.TableName)
                            .SetColumns(updateBatchDataReq.SingleField, updateBatchDataReq.NewValue)
                            .Where($"\"{updateBatchDataReq.SingleField}\" = @OldValue", new { OldValue = updateBatchDataReq.OldValue })
                            .ExecuteCommandAsync();
                    }

                }

                if (db.Commit())
                {
                    result.Result = true;
                    return result;
                }
                else
                {
                    result.Result = false;
                    result.Message = "修改失败";
                    return result;
                }
            }

        }
    }
}
