using System.Data;
using System.IO.Compression;
using System.Text;
using Infrastructure;
using Infrastructure.Extensions;
using Microsoft.Extensions.Options;
using NetTopologySuite;
using NetTopologySuite.Geometries;
using NetTopologySuite.IO;
using NetTopologySuite.IO.Esri;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using OpenAuth.App.BaseApp.Base;
using OpenAuth.App.BasicQueryService;
using OpenAuth.App.FormScheme;
using OpenAuth.App.FormScheme.FormHelpers;
using OpenAuth.App.Interface;
using OpenAuth.App.Request;
using OpenAuth.App.Response;
using OpenAuth.App.ServiceApp.ShpGeo.Request;
using OpenAuth.App.ServiceApp.ShpGeo.Utils;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using SqlSugar;
using Shapefile = NetTopologySuite.IO.Esri.Shapefile;

namespace OpenAuth.App.ServiceApp.ShpGeo;

public class ShpGeoLayerApp : SqlSugarBaseApp<ShpGeoLayer, SugarDbContext>
{
    private readonly string _filePath;
    private readonly ISqlSugarClient _client;
    CommonDataManager _commonDataManager;
    public ShpGeoLayerApp(ISugarUnitOfWork<SugarDbContext> unitWork,
        ISimpleClient<ShpGeoLayer> repository, IAuth auth, FormSchemeApp formSchemeApp,
        IOptions<AppSetting> setOptions, ISqlSugarClient client, CommonDataManager commonDataManager) : base(unitWork, repository, auth)
    {
        _client = client;
        _filePath = setOptions.Value.UploadPath;
        if (string.IsNullOrEmpty(_filePath))
        {
            _filePath = AppContext.BaseDirectory;
        }

        _commonDataManager = commonDataManager;
    }


    /// <summary>
    ///  添加geo图层
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public async Task<Response<bool>> Add(ShpGeoLayerShpReq obj)
    {
        var record = obj.MapTo<ShpGeoLayer>();
        record.CreateTime = DateTime.Now;
        record.UpdateTime = DateTime.Now;
        record.Id = Guid.NewGuid().ToString();
        using var db = Repository.AsSugarClient();
        if (db.DbMaintenance.IsAnyTable(obj.DataTable, false))
        {
            throw new Exception(obj.DataTable + "数据表已存在");
        }

        var layer = await Repository.AsQueryable().Where(a => a.DataTable.Equals(obj.DataTable)).FirstAsync();
        if (layer != null)
        {
            throw new Exception($"图层记录数据表名{obj.DataTable}已存在");
        }

        // 发布图层
        if (record.DataSourceType.Equals("shp"))
        {
            /*
           // 相对路径
           var sldFile = record.AppendPath;
           // 取得全路径
           var sldPath = Path.Combine(_filePath, sldFile);
           // 处理SLD
          var isSuccess = await GeoUtil.PublishSldStyle(sldPath, obj.DataTable);
           if (!isSuccess)
           {
               throw new Exception("SLD样式发布失败");
           }*/

            var response = await CreateDataTable(obj);
            if (!response.Result)
            {
                throw new Exception("创建shp数据表失败");
            }

            //  配置存储仓库及发布图层
            //var sldName = Path.GetFileName(sldFile);
            //var sldName = Path.GetFileNameWithoutExtension(sldFile);
            var result =
                await GeoUtil.CreateStoreAndLayer("", obj.SpatialRef, obj.DataTable, obj.StyleName);
            if (!result)
            {
                db.DbMaintenance.DropTable(obj.DataTable);
                throw new Exception("发布图层失败");
            }
        }
        else // excel 
        {
            var excelPath = Path.Combine(_filePath, obj.ShpPath);
            var excelFileName = Path.GetFileNameWithoutExtension(excelPath);
            // xls xlsx 
            // 使用NPOI读取Excel文件
            using (var fileStream = new FileStream(excelPath, FileMode.Open, FileAccess.Read))
            {
                IWorkbook workbook;
                if (Path.GetExtension(excelPath).Equals(".xls"))
                {
                    workbook = new HSSFWorkbook(fileStream);
                }
                else
                {
                    workbook = new XSSFWorkbook(fileStream);
                }

                var sheet = workbook.GetSheetAt(0);
                // 获取总行数
                var rowCount = sheet.LastRowNum;
                if (rowCount < 3)
                {
                    throw new Exception("只有两行表头");
                }

                // 获取总列数
                var columnCount = sheet.GetRow(0).LastCellNum;
                var headers = new List<DataTableAttr>();
                // 遍历表头
                var chineseRow = sheet.GetRow(0);
                var englishRow = sheet.GetRow(1);

                for (var j = 0; j < columnCount; j++)
                {
                    var header = new DataTableAttr
                    {
                        InitName = chineseRow.GetCell(j).ToString(),
                        RefName = englishRow.GetCell(j).ToString()?.ToLower(),
                        // 字段类型
                        Type = "string",
                        // 原始字段名称
                        Name = englishRow.GetCell(j).ToString(),
                        // 字段长度
                        Length = 64
                    };
                    headers.Add(header);
                }

                var keys = headers.Select(a => a.RefName).ToList();
                if (!keys.Contains("lng") || !keys.Contains("lat"))
                {
                    throw new Exception("缺少经纬度字段");
                }


                var typeBuilder = db.DynamicBuilder().CreateClass(obj.DataTable,
                    new SugarTable() { TableName = obj.DataTable, TableDescription = obj.ServerName + "图斑" });
                //添加主键
                typeBuilder.CreateProperty("id", typeof(string), new SugarColumn()
                {
                    IsPrimaryKey = true,
                    IsIdentity = false,
                    ColumnDataType = "varchar",
                    Length = 36,
                    ColumnDescription = "主键",
                });
                //添加主键
                typeBuilder.CreateProperty("geometry", typeof(string), new SugarColumn()
                {
                    IsPrimaryKey = false,
                    IsIdentity = false,
                    // ColumnDataType = "geometry(GEOMETRY)",
                    ColumnDataType = string.Concat("geometry(GEOMETRY,",
                        obj.SpatialRef.AsSpan(obj.SpatialRef.LastIndexOf(":", StringComparison.Ordinal) + 1),
                        ")"),
                    ColumnDescription = "图斑",
                });

                headers.ForEach(u =>
                {
                    if (!u.RefName.Equals("lng") && !u.RefName.Equals("lat"))
                    {
                        typeBuilder.CreateProperty(u.RefName, typeof(string), new SugarColumn()
                        {
                            IsPrimaryKey = false,
                            IsIdentity = false,
                            IsNullable = true,
                            Length = u.Length,
                            ColumnDescription = u.InitName,
                        });
                    }
                });
                // 开启事务
                await db.Ado.BeginTranAsync(IsolationLevel.ReadCommitted);
                // 创建表
                db.CodeFirst.InitTables(typeBuilder.BuilderType());

                var cols = new string[headers.Count];
                for (var i = 0; i < headers.Count; i++)
                {
                    if (headers[i].RefName.Equals("lng"))
                    {
                        cols[i] = "geometry";
                    }
                    else if (headers[i].RefName.Equals("lat"))
                    {
                        cols[i] = "id";
                    }
                    else
                    {
                        cols[i] = headers[i].RefName;
                    }
                }

                // 遍历数据行
                for (var i = 2; i < rowCount; i++)
                {
                    var row = sheet.GetRow(i);
                    if (row == null)
                    {
                        continue;
                    }

                    var data = new Dictionary<string, object>();
                    // 遍历列
                    string lat = null, lng = null;
                    for (var j = 0; j < columnCount; j++)
                    {
                        var cell = row.GetCell(j);
                        if (cell == null)
                        {
                            continue;
                        }

                        var cellValue = cell.ToString();
                        switch (headers[j].RefName)
                        {
                            case "lat":
                                lat = cellValue;
                                continue;
                            case "lng":
                                lng = cellValue;
                                continue;
                            default:
                                data[headers[j].RefName] = cellValue;
                                break;
                        }
                    }

                    if (lat != null && lng != null)
                    {
                        var geography =
                            NtsGeometryServices.Instance.CreateGeometryFactory(
                                int.Parse(obj.SpatialRef.Substring(
                                    obj.SpatialRef.IndexOf(":", StringComparison.Ordinal) + 1)));
                        var point = geography.CreatePoint(new Coordinate(double.Parse(lng), double.Parse(lat)));
                        data["geometry"] = point.AsText();
                    }

                    data["id"] = Guid.NewGuid().ToString();
                    await db.Insertable(data)
                        .AS(obj.DataTable) // 指定目标表名
                        .InsertColumns(cols) // 指定要插入的列
                        .ExecuteCommandAsync();
                }

                await db.Ado.CommitTranAsync();
                // 关于图层发布失败后，如何处理？
                // excel 矢量点发布图层 
                var response = await GeoUtil.CreateStoreAndLayer("", obj.SpatialRef, obj.DataTable, "");
                if (!response)
                {
                    // 如果图层发布失败 删除数据表
                    db.DbMaintenance.DropTable(obj.DataTable);
                }

                workbook.Close();
            }
        }

        var geoserver = GeoUtil.GeoserverUrl;
        var workspace = GeoUtil.Workspace;
        var storeName = GeoUtil.DbStoreName;
        var getBboxResponse = await GeoUtil.GetDBLayerBBox(workspace, storeName, obj.DataTable);
        if (getBboxResponse.Code == 200)
        {
            var bbox = getBboxResponse.Result;
            var serverUrl = $"{geoserver}/{workspace}/wms" +
                            $"?service=WMS" +
                            $"&version=1.1.0" +
                            $"&request=GetMap" +
                            $"&layers={workspace}:{obj.DataTable}" +
                            $"&bbox=" + bbox +
                            $"&width=768&height=619" +
                            $"&srs=" + obj.SpatialRef +
                            "&styles=" +
                            /*$"&styles=" + (obj.DataSourceType.Equals("shp")
                                    ? Path.GetFileName(obj.AppendPath)?.Replace(".sld", "")
                                    : "") +*/
                            $"&format=application/openlayers";
            record.ServerUrl = serverUrl;
            var pbfUrl = $"{geoserver}/gwc/service/tms/1.0.0/{workspace}:{obj.DataTable}@{obj.SpatialRef}@pbf";
            record.PbfUrl = pbfUrl;
        }

        var settingResponse = await GeoUtil.SettingLayerReturnFormat("", obj.DataTable);
        if (!settingResponse.Result)
        {
            // 设置返回格式失败
        }

        var flag = await Repository.InsertAsync(record);
        return new Response<bool>
        {
            Result = flag,
            Message = flag && getBboxResponse.Code == 200 ? "success" : flag ? "成功但获取serverurl失败" : "error"
        };
    }

    public async Task<Response<PageInfo<List<ShpGeoLayer>>>> LoadPage(ShpGeoLayerReq req)
    {
        RefAsync<int> totalCount = 0;
        var sources = await base.Repository.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(req.SererName), a => a.ServerName.Contains(req.SererName))
            .WhereIF(!string.IsNullOrEmpty(req.startTime) && !string.IsNullOrEmpty(req.endTime), a =>
                SqlFunc.Between(a.CreateTime, Convert.ToDateTime(req.startTime),
                    Convert.ToDateTime(req.endTime))) // 时间段查询
            .ToPageListAsync(req.page, req.limit, totalCount);

        return new Response<PageInfo<List<ShpGeoLayer>>>
        {
            Result = new PageInfo<List<ShpGeoLayer>>
            {
                Items = sources,
                Total = totalCount
            }
        };
    }

    public ShpGeoLayer Get(string id)
    {
        return Repository.GetById(id);
    }

    private static async Task UnZip(string zipFilePath, string extractPath)
    {
        await Task.Run(() =>
        {
            Directory.CreateDirectory(extractPath);
            // 设置字符编码
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            var gbk = Encoding.GetEncoding("utf-8");
            using (var archive = ZipFile.OpenRead(zipFilePath))
            {
                // 列举ZIP文件中的条目
                foreach (var entry in archive.Entries)
                {
                    var xxx = gbk.GetString(Encoding.Default.GetBytes(entry.FullName));
                    Console.WriteLine(xxx);
                }

                // 提取ZIP文件中的所有文件到指定目录

                foreach (var entry in archive.Entries)
                {
                    if (entry.Name != string.Empty)
                    {
                        // 确保完整路径存在  entry.FullName 是否可以编码
                        var fixedEntryName = entry.FullName.Replace("/", "");
                        var destinationPath = Path.GetFullPath(Path.Combine(extractPath, fixedEntryName));
                        Console.WriteLine("解压文件路径：" + destinationPath);
                        if (!destinationPath.StartsWith(Path.GetFullPath(extractPath) + Path.DirectorySeparatorChar))
                        {
                            throw new UnauthorizedAccessException("试图提取的文件超出了目标文件夹的路径边界。");
                        }

                        // 提取条目到目标路径
                        entry.ExtractToFile(destinationPath, overwrite: true);
                    }
                }
            }

            // 遍历解压目录，是否有shp后缀的文件
            if (!Directory.Exists(extractPath))
            {
                throw new Exception("文件解压失败");
            }
        });
    }

    private static void DeleteFile(string extractPath)
    {
        try
        {
            // 递归删除目录和其内容
            Directory.Delete(extractPath, true);
            Console.WriteLine("解压目录删除成功");
        }
        catch (IOException ex)
        {
            Console.WriteLine("解压目录不能删除: " + ex.Message);
        }
        catch (UnauthorizedAccessException ex)
        {
            Console.WriteLine("没有权限删除解压目录: " + ex.Message);
        }
    }


    private static string MapDbaseTypeToPostgresString(char dbaseType)
    {
        return dbaseType switch
        {
            'C' => "varchar",
            'N' => "numeric",
            'L' => "boolean",
            'D' => "date",
            'M' => "text",
            _ => "varchar"
        };
    }


    public async Task<Response<bool>> Test(string tableName, string serverName, string srid, string shpPath)
    {
        using var db = Repository.AsSugarClient();

        // 校验 表是否存在
        var isExists = db.DbMaintenance.IsAnyTable(tableName, false);
        if (isExists)
        {
            //throw new Exception(tableName + "该数据库表已存在");
            db.DbMaintenance.DropTable(tableName);
        }

        var shpGeoLayer = await db.Queryable<ShpGeoLayer>()
            .Where(c => c.ServerName.Equals(serverName))
            .FirstAsync();
        if (!shpGeoLayer.IsNullOrEmpty())
        {
            throw new Exception("服务名已存在");
        }

        //  插入图斑数据
        shpPath = Path.Combine(_filePath, shpPath);
        var extractPath = shpPath.Substring(0, shpPath.LastIndexOf(".", StringComparison.Ordinal)) + "extract";
        await UnZip(shpPath, extractPath);
        var searchPattern = "*.shp"; // 设置你想要遍历的文件后缀名
        var fileName = Directory.GetFiles(extractPath, searchPattern, SearchOption.AllDirectories);
        if (fileName.IsEmpty())
        {
            throw new Exception("未找到shp文件");
        }

        string shpFileName = fileName[0];
        // shpFile 文件路径
        string shpFile = Path.Combine(extractPath, shpFileName);
        var rows = new List<Dictionary<string, object>>();

        using (var dataReader = new ShapefileDataReader(shpFile, GeometryFactory.Default))
        {
            var headers = new List<DataTableAttr>();

            for (var i = 0; i < dataReader.DbaseHeader.NumFields; i++)
            {
                var colAttr = new DataTableAttr();
                //colAttr.DataType = dataReader.DbaseHeader.Fields[i].Type;
                colAttr.RefName = dataReader.DbaseHeader.Fields[i].Name;
                colAttr.InitName = dataReader.DbaseHeader.Fields[i].Name;
                colAttr.Length = dataReader.DbaseHeader.Fields[i].Length;
                headers.Add(colAttr);
            }

            // 创建数据表
            var typeBuilder = db.DynamicBuilder().CreateClass(tableName,
                new SugarTable() { TableName = tableName, TableDescription = serverName + "图斑" });
            //添加主键
            typeBuilder.CreateProperty("id", typeof(string), new SugarColumn()
            {
                IsPrimaryKey = true,
                IsIdentity = false,
                ColumnDataType = "varchar",
                Length = 36,
                ColumnDescription = "主键",
            });
            typeBuilder.CreateProperty("Geometry", typeof(string), new SugarColumn()
            {
                IsPrimaryKey = false,
                IsIdentity = false,
                ColumnDataType = string.Concat("geometry(GEOMETRY, ",
                    srid.AsSpan(srid.LastIndexOf(":", StringComparison.Ordinal) + 1), ")"),
                ColumnDescription = "图斑",
            });
            headers.ForEach(u =>
            {
                typeBuilder.CreateProperty(u.RefName, typeof(string), new SugarColumn()
                {
                    IsPrimaryKey = false,
                    IsIdentity = false,
                    //ColumnDataType = u.Type,
                    IsNullable = true,
                    Length = u.Length,
                    ColumnDescription = u.InitName,
                });
            });
            // 开启事务
            await db.Ado.BeginTranAsync(IsolationLevel.ReadCommitted);
            // 创建表
            db.CodeFirst.InitTables(typeBuilder.BuilderType());
            var x = 0;
            List<string> cols = new List<string>();
            // 读取一下行数据
            while (dataReader.Read() && x++ < 20)
            {
                // 增加 id 及
                // var cols = new string[dataReader.DbaseHeader.NumFields + 2];
                var insertObj = new Dictionary<string, object>
                {
                    { "id", Guid.NewGuid().ToString() }
                };
                Console.Write("类型： " + dataReader.Geometry.GeometryType);
                // 读取一行数据
                for (int i = 0, j = 0; i < dataReader.FieldCount; i++)
                {
                    cols.Add(dataReader.GetName(i));
                    if (dataReader.GetName(i).ToLower().Equals("geometry"))
                    {
                        var geom = dataReader.GetValue(i) as Geometry;
                        //var srid = geom.SRID;
                        insertObj.Add(dataReader.GetName(i), geom.AsText());
                    }
                    else
                    {
                        insertObj.Add(dataReader.GetName(i), dataReader.GetValue(i));
                    }
                }

                rows.Add(insertObj);
            }

            /*await db.Insertable(rows)
    .AS(tableName) // 指定目标表名
    //.InsertColumns(cols) // 指定要插入的列
    .ExecuteCommandAsync();*/
            var sql = "INSERT INTO \"public\".\"" + tableName + "\" (";
            // to do 
            var colsStr = "";
            foreach (var key in rows.First().Keys)
            {
                colsStr += "\"" + key + "\",";
            }

            colsStr = colsStr.Substring(0, colsStr.Length - 1);
            sql += colsStr + ") VALUES (";
            var values = "";
            foreach (var dictionary in rows)
            {
                // todo 如何处理 geometry 类型
                foreach (var value in dictionary.Values)
                {
                    values += "'" + value + "',";
                }
            }

            await db.Ado.ExecuteCommandAsync(sql);
            await db.Ado.CommitTranAsync();
        }


        return new Response<bool>()
        {
            Result = true,
            Message = "ok"
        };
    }


    /// <summary>
    /// 图层更新
    /// </summary>
    /// <param name="updateLayerReq"></param>
    /// <returns></returns>
    public async Task<Response<bool>> UpdateLayer(UpdateGeoLayerShpReq updateLayerReq)
    {
        var db = Repository.AsSugarClient();
        await db.Ado.BeginTranAsync();
        var layer = await Repository.GetByIdAsync(updateLayerReq.Id);
        //var styleName = layer.StyleName; // 前面使用表名作为样式名称
        var newStyleName = updateLayerReq.StyleName;
        var result = await GeoUtil.UpdateStyle(GeoContext.Instance.Workspace, layer.DataTable, newStyleName);
        /*  if (!string.IsNullOrEmpty(updateLayerReq.sldPath))
          {
              // 更新样式
              // 取得全路径
              // var sldPath = Path.Combine(_filePath, updateLayerReq.sldPath);
              var response = await GeoUtil.UpdateSldStyle(sldPath, styleName);
              if (!response)
              {
                  throw new Exception("样式更新失败");
              }
        }*/
        if (!result.Result)
        {
            throw new Exception("更换样式失败");
        }

        var record = updateLayerReq.MapTo<ShpGeoLayer>();
        await db.Updateable(record).IgnoreNullColumns().ExecuteCommandAsync();
        await db.Ado.CommitTranAsync();
        return new Response<bool>()
        {
            Result = true,
            Message = "更新成功"
        };
    }

    /// <summary>
    /// 删除图层
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<Response<bool>> Delete(string id)
    {
        var db = Repository.AsSugarClient();
        await db.Ado.BeginTranAsync();

        var shp = await Repository.GetByIdAsync(id);
        var dataTable = shp.DataTable;
        db.DbMaintenance.DropTable(dataTable);
        // todo 删除对应图层
        await db.Deleteable<ShpGeoLayer>().Where(c => c.Id.Equals(id)).ExecuteCommandAsync();
        await db.Ado.CommitTranAsync();
        return new Response<bool>()
        {
            Result = true,
            Message = "删除成功"
        };
    }

    public async Task<Response<ShpInfo>> ParseShpInfo(string zipFilePath, string tableName,
        string srid)
    {
        using var db = Repository.AsSugarClient();
        // 开启事务

        if (db.DbMaintenance.IsAnyTable(tableName))
        {
            throw new Exception("表名已存在");
        }

        // 取得文件完全路径
        zipFilePath = Path.Combine(_filePath, zipFilePath);
        // 确保ZIP文件存在
        if (!File.Exists(zipFilePath))
        {
            throw new FileNotFoundException("ZIP文件未找到。");
        }

        var exist = await db.Queryable<ShpGeoLayer>()
            .Where(c => c.DataType.Equals(tableName))
            .CountAsync();
        if (exist > 0)
        {
            throw new Exception(tableName + "表名已存在");
        }

        // 打开ZIP存档 取除后缀之前的字符串
        var extractPath = zipFilePath.Substring(0, zipFilePath.LastIndexOf(".", StringComparison.Ordinal)) +
                          "extract";
        // 解压文件
        await UnZip(zipFilePath, extractPath);
        var searchPattern = "*.shp"; // 设置你想要遍历的文件后缀名
        var fileName = Directory.GetFiles(extractPath, searchPattern, SearchOption.AllDirectories);
        if (fileName.IsEmpty())
        {
            throw new Exception("压缩文件中无shp文件");
        }

        var shpFileName = fileName[0];
        var shpFile = Path.Combine(extractPath, shpFileName);
        var shapeType = Shapefile.GetShapeType(shpFile);
        var shpInfo = new ShpInfo();
        switch (shapeType)
        {
            case ShapeType.Point:
                shpInfo.DataType = "点";
                break;
            case ShapeType.Polygon:
                shpInfo.DataType = "面";
                break;
            case ShapeType.PolyLine:
                shpInfo.DataType = "线";
                break;
            default:
                throw new Exception("不支持的shp类型: " + shapeType);
        }

        var attrs = new List<DataTableAttr>();
        // 添加自定义字段
        var geom = new DataTableAttr
        {
            Name = "Geometry",
            Type = string.Concat("geometry(GEOMETRY,",
                srid.AsSpan(srid.LastIndexOf(":", StringComparison.Ordinal) + 1),
                ")")
        };
        attrs.Add(geom);
        using (var reader = new ShapefileDataReader(shpFile, GeometryFactory.Default))
        {
            // 获取DbfDataReader，用于读取属性信息
            var dbfReader = reader.DbaseHeader;
            foreach (var dbaseFieldDescriptor in dbfReader.Fields)
            {
                DataTableAttr attr = new DataTableAttr();
                attr.Name = dbaseFieldDescriptor.Name;
                attr.Length = dbaseFieldDescriptor.Length;
                attr.Type = MapDbaseTypeToPostgresString(dbaseFieldDescriptor.DbaseType);
                attrs.Add(attr);
            }
        }

        shpInfo.Headers = attrs;
        shpInfo.TableName = tableName;
        return new Response<ShpInfo>()
        {
            Result = shpInfo,
            Message = "ok"
        };
    }

    // todo 拆分，主方法中完成数据库操作，
    public async Task<Response<bool>> CreateDataTable(ShpGeoLayerShpReq shpInfo)
    {
        using var db = Repository.AsSugarClient();

        var tableName = shpInfo.DataTable;
        // 校验 表是否存在
        var exist = await db.Queryable<ShpGeoLayer>()
            .Where(c => c.DataTable.Equals(tableName))
            .CountAsync();
        if (exist > 0)
        {
            throw new Exception(tableName + "库表名称已存在");
        }

        var shpGeoLayer = await db.Queryable<ShpGeoLayer>()
            .Where(c => c.ServerName.Equals(shpInfo.ServerName))
            .FirstAsync();
        if (!shpGeoLayer.IsNullOrEmpty())
        {
            throw new Exception("未执行shp解析");
        }

        // 创建数据表
        var typeBuilder = db.DynamicBuilder().CreateClass(tableName,
            new SugarTable() { TableName = tableName, TableDescription = shpInfo.ServerName + "图斑" });
        //添加主键
        typeBuilder.CreateProperty("id", typeof(string), new SugarColumn()
        {
            IsPrimaryKey = true,
            IsIdentity = false,
            ColumnDataType = "varchar",
            Length = 36,
            ColumnDescription = "主键",
        });

        shpInfo.Headers.ForEach(u =>
        {
            typeBuilder.CreateProperty(u.RefName, typeof(string), new SugarColumn()
            {
                IsPrimaryKey = false,
                IsIdentity = false,
                ColumnDataType = u.Type,
                IsNullable = true,
                Length = u.Length,
                ColumnDescription = u.InitName,
            });
        });
        // 开启事务
        await db.Ado.BeginTranAsync(IsolationLevel.ReadCommitted);
        // 创建表
        db.CodeFirst.InitTables(typeBuilder.BuilderType());

        //  插入图斑数据
        var shpPath = Path.Combine(_filePath, shpInfo.ShpPath);
        var extractPath = shpPath.Substring(0, shpPath.LastIndexOf(".", StringComparison.Ordinal)) + "extract";
        var searchPattern = "*.shp"; // 设置你想要遍历的文件后缀名
        var fileName = Directory.GetFiles(extractPath, searchPattern, SearchOption.AllDirectories);
        if (fileName.IsEmpty())
        {
            throw new Exception("未找到shp文件");
        }

        var shpFileName = fileName[0];
        // shpFile 文件路径
        var shpFile = Path.Combine(extractPath, shpFileName);
        shpInfo.Headers.Add(new DataTableAttr
        {
            RefName = "",
            InitName = "",
            Name = ""
        });

        // 批量插入
        var cols = new string[shpInfo.Headers.Count];
        for (var i = 0; i < shpInfo.Headers.Count - 1; i++)
        {
            cols[i] = shpInfo.Headers[i].RefName;
        }

        cols[^1] = "id";
        using (var dataReader = new ShapefileDataReader(shpFile, GeometryFactory.Default))
        {
            Console.WriteLine("记录数" + dataReader.RecordCount);
            //throw new Exception("失败");
            var objs = new List<Dictionary<string, object>>(1001);
            var num = 0;
            int count = 0;
            while (dataReader.Read())
            {
                count++;
                Console.WriteLine("记录行：" + count);
                var insertObj = new Dictionary<string, object>
                {
                    { "id", Guid.NewGuid().ToString() }
                };
                // 读取列
                for (int i = 0, j = 0; i < dataReader.FieldCount; i++)
                {
                    var colName = dataReader.GetName(i);
                    var header = shpInfo.Headers[j];
                    if (header.Name.Equals(colName))
                    {
                        if (colName.ToLower().Equals("geometry"))
                        {
                            var geometry = (Geometry)dataReader.GetValue(i);
                            var srid = shpInfo.SpatialRef.Substring(
                                shpInfo.SpatialRef.IndexOf(":", StringComparison.Ordinal) + 1);
                            var geometryForWgs84 = GeometryFactory.Default.WithSRID(int.Parse(srid))
                                .CreateGeometry(geometry);
                            insertObj.Add(shpInfo.Headers[j++].RefName, geometryForWgs84.AsText());
                        }
                        else
                        {
                            insertObj.Add(shpInfo.Headers[j++].RefName, dataReader.GetValue(i));
                        }
                    }
                }

                objs.Add(insertObj);
                if (num++ == 999)
                {
                    await db.Insertable(objs)
                        .AS(tableName) // 指定目标表名
                        .InsertColumns(cols) // 指定要插入的列
                        .ExecuteCommandAsync();
                    num = 0;
                    objs.Clear();
                }
            }

            // 读取末尾
            await db.Insertable(objs)
                .AS(tableName) // 指定目标表名
                .InsertColumns(cols) // 指定要插入的列
                .ExecuteCommandAsync();
        }

        await db.Ado.CommitTranAsync();
        // 删文件
        //DeleteFile(extractPath);
        return new Response<bool>()
        {
            Result = true,
            Message = "ok"
        };
    }

    public async Task<Response<bool>> Test1(string tableName, string serverName, string srid, string shpPath)
    {
        var db = Repository.AsSugarClient();


        // 输出目
        /*var db = Repository.AsSugarClient();
        shpPath = Path.Combine(_filePath, shpPath);
        var extractPath = shpPath.Substring(0, shpPath.LastIndexOf(".", StringComparison.Ordinal)) + "extract";
        var searchPattern = "*.shp"; // 设置你想要遍历的文件后缀名
        var fileName = Directory.GetFiles(extractPath, searchPattern, SearchOption.AllDirectories);
        if (fileName.IsEmpty())
        {
            throw new Exception("未找到shp文件");
        }

        var shpFileName = fileName[0];
        // shpFile 文件路径
        var shpFile = Path.Combine(extractPath, shpFileName);
        await db.Ado.BeginTranAsync();
        var rows = new List<Dictionary<string, object>>();
        using (var dataReader = new ShapefileDataReader(shpFile, GeometryFactory.Default))
        {
            while (dataReader.Read())
            {
                var insertObj = new Dictionary<string, object>
                {
                    { "id", Guid.NewGuid().ToString() },
                    { "geometry", dataReader.Geometry.AsBinary() },
                };
                rows.Add(insertObj);
            }
        }

        int insertCount = await db.Insertable(rows)
            .AS(tableName) // 指定目标表名
            .InsertColumns("id", "geometry") // 指定要插入的列
            .ExecuteCommandAsync();
        /*
        foreach (var geometry in Shapefile.ReadAllGeometries(shpFile))
        {
            var insertObj = new Dictionary<string, object>
            {
                { "id", Guid.NewGuid().ToString() },
                { "geometry", geometry.AsBinary() },
            };
            int insertCount = await db.Insertable(insertObj)
                .AS(tableName) // 指定目标表名
                .InsertColumns("id", "geometry") // 指定要插入的列
                .ExecuteCommandAsync();
        }
        #1#

        await db.Ado.CommitTranAsync();*/
        return new Response<bool>
        {
            Result = true
        };
    }

    /// <summary>
    /// 获取图层中心点
    /// </summary>
    /// <param name="tableName"></param>
    /// <returns></returns>
    public async Task<Response<string>> GetGeomData(string tableName)
    {
        var sql = "select ST_AsText(ST_Centroid(ST_Extent(geometry))) from \"public\".\"" + tableName + "\"";
        var db = Repository.AsSugarClient();
        var result = await db.Ado.SqlQuerySingleAsync<string>(sql);
        return new Response<string>
        {
            Result = result,
            Message = "ok"
        };
    }

    public byte[] QueryVectorTileByTable1(QueryVectorTileByTableReq req)
    {
        VectorTileSearchModel searchModel = new VectorTileSearchModel
        {
            x = req.x,
            y = req.y,
            z = req.z,
            //field = req.field,
            table = req.table,
            filter = req.filter,
        };

        var fieldArray = req.field.TrimEnd(',').Split(",");
        //req  fields 
        var fields = "";
        var cols = _client.DbMaintenance.GetColumnInfosByTableName(req.table);
        foreach (var dbColumnInfo in cols)
        {
            if (dbColumnInfo.DbColumnName.Equals("geometry"))
            {
                continue;
            }

            fields += dbColumnInfo.DbColumnName + ",";
        }

        fields = fields.TrimEnd(',');
        var fieldArrayTemp = fields.Split(",");
        // 取两个数组的交集
        fields = string.Join(",", fieldArrayTemp.Intersect(fieldArray)) + ",";
        searchModel.field = fields;
        var result = _commonDataManager.VectorTile1(searchModel);
        return result;
    }

    #region 获取矢量切片

    /// <summary>
    /// 根据表名获取矢量切片
    /// </summary>
    /// <param name="req"></param>
    /// <returns></returns>
    public byte[] QueryVectorTileByTable(QueryVectorTileByTableReq req)
    {
        VectorTileSearchModel searchModel = new VectorTileSearchModel
        {
            x = req.x,
            y = req.y,
            z = req.z,
            field = req.field,
            table = req.table,
            filter = req.filter,
        };
        var result = new CommonDataManager(base.UnitWork.CreateContext().Db).VectorTile(searchModel);
        return result;
    }

    #endregion

    public dynamic GetDataTableRecord(string dataTable, string id)
    {
        using var db = Repository.AsSugarClient();
        var list = db.DbMaintenance.GetColumnInfosByTableName(dataTable);
        var fields = string.Join(",", list.Where(x => x.DbColumnName != "geometry").Select(x => x.DbColumnName));
        return db.Ado.SqlQuery<dynamic>("select " + fields + " from " + dataTable + " where id='" + id + "'").First();
    }
}