using System.Data;
using Infrastructure;
using Infrastructure.Utils;
using Microsoft.Extensions.Options;
using NetTopologySuite;
using NetTopologySuite.Geometries;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using OpenAuth.App.BaseApp.Base;
using OpenAuth.App.Interface;
using OpenAuth.App.ServiceApp.LayerManagerApp.Request;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using SqlSugar;

namespace OpenAuth.App.ServiceApp.LayerManagerApp;

public class LayerApp : SqlSugarBaseApp<DmLayer, SugarDbContext>
{
    private readonly string _filePath;
    private readonly ISqlSugarClient _client;

    public LayerApp(ISugarUnitOfWork<SugarDbContext> unitWork,
        ISimpleClient<DmLayer> repository, IAuth auth,
        IOptions<AppSetting> setOptions, ISqlSugarClient client) : base(unitWork, repository, auth)
    {
        _client = client;
        _filePath = setOptions.Value.UploadPath;
        if (string.IsNullOrEmpty(_filePath))
        {
            _filePath = AppContext.BaseDirectory;
        }
    }

    public async Task<Response<bool>> UploadExcel(LayerReq req)
    {
        using var db = Repository.AsSugarClient();
        var excelPath = Path.Combine(_filePath, req.FilePath);
        // excel名称
        var excelFileName = Path.GetFileNameWithoutExtension(excelPath);
        // 使用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(req.DataTable,
                new SugarTable() { TableName = req.DataTable, TableDescription = req.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,",
                    req.SpatialRef.AsSpan(req.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;
                }
            }

            var objs = new List<Dictionary<string, object>>(1001);
            var num = 0;
            // 遍历数据行
            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(req.SpatialRef.Substring(
                                req.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();
                objs.Add(data);
                if (num++ == 999)
                {
                    await db.Insertable(objs)
                        .AS(req.DataTable) // 指定目标表名
                        .InsertColumns(cols) // 指定要插入的列
                        .ExecuteCommandAsync();
                    num = 0;
                    objs.Clear();
                }
            }

            await db.Insertable(objs)
                .AS(req.DataTable) // 指定目标表名
                .InsertColumns(cols) // 指定要插入的列
                .ExecuteCommandAsync();
            await db.Ado.CommitTranAsync();
            workbook.Close();
            // 关于图层发布失败后，如何处理？
            // excel 矢量点发布图层 
            var response = await GeoUtil.CreateStoreAndLayer("", req.SpatialRef, req.DataTable, "");
            // todo  保存图层信息
            var dmLayer = new DmLayer()
            {
                Id = Guid.NewGuid().ToString(),
                SeverName = req.ServerName,
                SpatialRef = req.SpatialRef,
                SeverType = req.SeverType, // 服务类型
                StoreType = "", //存储类型
                DataSourceType = req.DataSourceType,
                TableRef = req.DataTable,
                ShapeType = req.ShapeType,
                StyleName = req.StyleName, // 样式名称
                Description = req.Description, // 描述
                Screenshot = req.Screenshot // 截图
            };
            await Repository.AsSugarClient().Insertable(dmLayer).ExecuteCommandAsync();
        }

        return new Response<bool>
        {
            Result = true
        };
    }

    public async Task<Response<bool>> UploadShape(LayerReq req)
    {
        try
        {
        }
        catch (Exception ex)
        {
            throw new CommonException(ex.Message, 500);
        }

        return new Response<bool>
        {
            Result = true
        };
    }
}