package com.goer.project.model.modelEntity.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;

import com.alibaba.fastjson.JSON;
import com.goer.common.chiner.model.ColumnField;
import com.goer.common.chiner.model.TableEntity;
import com.goer.common.command.AbstractDBCommand;
import com.goer.common.command.ExecResult;
import com.goer.common.command.impl.DBReverseGetTableDDLImpl;
import com.goer.common.utils.DateUtils;
import com.goer.common.utils.StringUtils;
import com.goer.common.utils.file.FileUtils;
import com.goer.common.utils.fisok.raw.kit.JSONKit;
import com.goer.common.utils.poi.ExcelHandlerAdapter;
import com.goer.common.utils.poi.ExcelUtil;
import com.goer.common.utils.reflect.ReflectUtils;
import com.goer.common.utils.security.ShiroUtils;
import com.goer.framework.aspectj.lang.annotation.Excel;
import com.goer.project.model.dataType.domain.DataType;
import com.goer.project.model.dataType.mapper.DataTypeMapper;
import com.goer.project.model.modelDbs.domain.ModelDbs;
import com.goer.project.model.modelDbs.mapper.ModelDbsMapper;
import com.goer.project.model.modelField.domain.ModelField;
import com.goer.project.model.modelField.mapper.ModelFieldMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.goer.project.model.modelEntity.mapper.ModelEntityMapper;
import com.goer.project.model.modelEntity.domain.ModelEntity;
import com.goer.project.model.modelEntity.service.IModelEntityService;
import com.goer.common.utils.text.Convert;

import static com.goer.common.utils.poi.ExcelUtil.getSheetPictures03;
import static com.goer.common.utils.poi.ExcelUtil.getSheetPictures07;

/**
 * 数据Service业务层处理
 * 
 * @author goer
 * @date 2022-01-17
 */
@Slf4j
@Service
public class ModelEntityServiceImpl implements IModelEntityService 
{
    @Autowired
    private ModelEntityMapper modelEntityMapper;
    @Autowired
    private ModelFieldMapper modelFieldMapper;
    @Autowired
    private ModelDbsMapper modelDbsMapper;
    @Autowired
    private DataTypeMapper dataTypeMapper;

    /**
     * 查询数据
     * 
     * @param id 数据主键
     * @return 数据
     */
    @Override
    public ModelEntity selectModelEntityById(Long id)
    {
        return modelEntityMapper.selectModelEntityById(id);
    }

    /**
     * 查询数据列表
     * 
     * @param modelEntity 数据
     * @return 数据
     */
    @Override
    public List<ModelEntity> selectModelEntityList(ModelEntity modelEntity)
    {
        return modelEntityMapper.selectModelEntityList(modelEntity);
    }

    /**
     * 新增数据
     * 
     * @param modelEntity 数据
     * @return 结果
     */
    @Override
    public int insertModelEntity(ModelEntity modelEntity)
    {
        int sort = modelEntityMapper.selectMaxEntitySort(modelEntity);
        modelEntity.setEntitySort(sort);
        modelEntity.setCreateTime(DateUtils.getNowDate());
        modelEntityMapper.insertModelEntity(modelEntity);
        return modelEntityMapper.initModelField(modelEntity);
    }

    /**
     * 复制数据
     *
     * @param modelEntity 数据
     * @return 结果
     */
    @Override
    public int copyModelEntity(ModelEntity modelEntity)
    {
        int rtn = 0;
        int sort = modelEntityMapper.selectMaxEntitySort(modelEntity);
        modelEntity.setEntitySort(sort);
        modelEntity.setCreateTime(DateUtils.getNowDate());
        rtn = modelEntityMapper.insertModelEntity(modelEntity);
        for (ModelField mf : modelEntity.getFields()) {
            mf.setEntityId(modelEntity.getId());
            mf.setCreateTime(DateUtils.getNowDate());
            rtn = rtn + modelFieldMapper.insertModelField(mf);
        }
        return rtn;
    }

    /**
     * 修改数据
     * 
     * @param modelEntity 数据
     * @return 结果
     */
    @Override
    public int updateModelEntity(ModelEntity modelEntity)
    {
        modelEntity.setUpdateTime(DateUtils.getNowDate());
        return modelEntityMapper.updateModelEntity(modelEntity);
    }

    /**
     * 批量删除数据
     * 
     * @param ids 需要删除的数据主键
     * @return 结果
     */
    @Override
    public int deleteModelEntityByIds(String ids)
    {
        return modelEntityMapper.deleteModelEntityByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除数据信息
     * 
     * @param id 数据主键
     * @return 结果
     */
    @Override
    public int deleteModelEntityById(Long id)
    {
        return modelEntityMapper.deleteModelEntityById(id);
    }

    /**
     * 排序
     *
     * @param modelEntity
     * @return
     */
    @Override
    public int sort(ModelEntity modelEntity) {
        int result = 0;
        int pageSize = 10;
        int pageNumber = 1;
        Object pz = modelEntity.getParams().get("pageSize");
        if (pz != null) {
            pageSize = Convert.toInt(pz, 10);
        }
        Object pn = modelEntity.getParams().get("pageNumber");
        if (pn != null) {
            pageNumber = Convert.toInt(pn, 1);
        }

        List<ModelEntity> list = modelEntity.getPramsByName("sortData", ModelEntity.class);
        if(list != null && !list.isEmpty()) {
            int idx = pageSize * (pageNumber - 1) + 1;
            for(ModelEntity mf : list) {
                mf.setUpdateBy(modelEntity.getUpdateBy());
                mf.setUpdateTime(modelEntity.getUpdateTime());
                mf.setEntitySort(idx ++);
            }
            result = modelEntityMapper.updateList(list);
        }
        return result;
    }

    /**
     * 逆向解析数据库导入
     *
     * @param modelEntity
     * @return
     */
    @Override
    public int importTable(ModelEntity modelEntity) {
        int ret = 0;
        DataType dataType = new DataType();
        dataType.setProjectId(modelEntity.getProjectId());
        dataType.setVersionId(0L);


//        ModelDbs modelDbs = modelDbsMapper.selectDefaultDbByProjectId(modelEntity.getProjectId());
        ModelDbs modelDbs = modelDbsMapper.selectModelDbsById(modelEntity.getId());

        DBReverseGetTableDDLImpl db = new DBReverseGetTableDDLImpl();
        Map<String, String> argsMap = new HashMap<String, String>();
        argsMap.put(AbstractDBCommand.KEY_DRIVER_CLASS_NAME,modelDbs.getDriverClassName());
        argsMap.put(AbstractDBCommand.KEY_URL,modelDbs.getUrl());
        argsMap.put(AbstractDBCommand.KEY_USERNAME,modelDbs.getUserName());
        argsMap.put(AbstractDBCommand.KEY_PASSWORD,modelDbs.getPassword());
        argsMap.put("tables",modelEntity.getEntityCode());
        ExecResult er = db.exec(argsMap);

        log.debug(JSONKit.toJsonString(er,true));

        List<TableEntity> listTable = (List<TableEntity>)er.getBody();
        for(TableEntity te : listTable) {
            ModelEntity ne = new ModelEntity();
            ne.setEntityCode(te.getDefKey());
            ne.setEntityName(te.getDefName());
            ne.setRemark(te.getComment());
            ne.setProjectId(modelEntity.getProjectId());
            ne.setVersionId(0L);
            ne.setCreateBy(modelEntity.getCreateBy());
            ne.setCreateTime(modelEntity.getCreateTime());

            int sort = modelEntityMapper.selectMaxEntitySort(ne);
            ne.setEntitySort(sort);

            ret = ret + modelEntityMapper.insertModelEntity(ne);

            List<ColumnField> listField = te.getFields();
            for(ColumnField cf : listField) {
//                "rowNo" : 1,
//                "defKey" : "id",
//                "defName" : "编号",
//                "comment" : "",
//                "domain" : "",
//                "type" : "BIGINT",
//                "len" : 20,
//                "scale" : null,
//                "primaryKey" : true,
//                "notNull" : true,
//                "autoIncrement" : true,
//                "defaultValue" : "",
//                "hideInGraph" : false,
//                "typeFullName" : "BIGINT(20)",
//                "primaryKeyName" : "√",
//                "notNullName" : "√",
//                "autoIncrementName" : "√",
//                "refDict" : ""
                ModelField mf = new ModelField();
                mf.setVersionId(0L);
                mf.setProjectId(modelEntity.getProjectId());
                mf.setEntityId(ne.getId());
                mf.setFieldName(cf.getDefName());
                mf.setFieldCode(cf.getDefKey());
                mf.setFieldType(cf.getTypeFullName());

                //
                dataType.setMysqlCode(cf.getTypeFullName());
                List<DataType> dataTypes = dataTypeMapper.selectDataTypeList(dataType);
                if(dataTypes == null || dataTypes.size() <= 0) {
                    DataType ndt = new DataType();
                    ndt.setProjectId(dataType.getProjectId());
                    ndt.setVersionId(0L);
                    ndt.setDataTypeName(cf.getTypeFullName());
                    ndt.setDataTypeCode(cf.getTypeFullName());
                    ndt.setMysqlCode(cf.getTypeFullName());

                    int sortDt = dataTypeMapper.selectMaxDataSort(dataType);
                    ndt.setDataSort(sortDt);
                    ndt.setCreateTime(DateUtils.getNowDate());
                    ndt.setCreateBy(modelEntity.getCreateBy());
                    dataTypeMapper.insertDataType(ndt);
                } else {
                    mf.setFieldType(dataTypes.get(0).getDataTypeCode());
                }

                mf.setFieldPk("N");
                if(cf.getPrimaryKey()) {
                    mf.setFieldPk("Y");
                }
                mf.setNotNull("N");
                if(cf.getNotNull()) {
                    mf.setNotNull("Y");
                }
                mf.setAutoIncrement("N");
                if(cf.getAutoIncrement()) {
                    mf.setAutoIncrement("Y");
                }
                mf.setDefaultValue(cf.getDefaultValue());
                mf.setFieldSort(cf.getRowNo());
                mf.setCreateBy(modelEntity.getCreateBy());
                mf.setCreateTime(modelEntity.getCreateTime());
                ret = ret + modelFieldMapper.insertModelField(mf);
            }
        }

        return ret;
    }

    public String checkEntityCodeUnique(ModelEntity modelEntity) {
        Long entityId = StringUtils.isNull(modelEntity.getId()) ? -1L : modelEntity.getId();
        ModelEntity info = null;
        if(StringUtils.isNotEmpty(modelEntity.getEntityCode())) {
            info = modelEntityMapper.checkEntityCodeUnique(modelEntity);
        }
        if (StringUtils.isNull(info)) {
            return "0";
        }
        if(info.getId().longValue() != entityId.longValue()) {
            return "1";
        }
        return "0";
    }

    /**
     * 导入文件表结构，转换成list
     *
     * @param is 输入流
     * @return 转换后集合
     */
    public int importTables(InputStream is, Long projectId) throws Exception
    {

        int rtn = 0;

        List<ModelEntity> mes = new ArrayList<>();

        Date nowDate = DateUtils.getNowDate();

        Workbook wb = WorkbookFactory.create(is);
        // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet
        int sheetCnt = wb.getNumberOfSheets();

        if (sheetCnt == 0) {
            throw new IOException("文件无sheet");
        }

        Sheet sheet = null;
        ModelEntity cond = new ModelEntity();
        cond.setProjectId(projectId);
        cond.setVersionId(0L);
        int intEntitySort = modelEntityMapper.selectMaxEntitySort(cond) + 1;

        for (int i=0;i<sheetCnt;i++) {

            sheet = wb.getSheetAt(i);
            // 获取表名称（中文）
            Row row1 = sheet.getRow(1);
            String tableName = null;
            if (row1.getCell(2) != null) {
                tableName = getCellValue(row1,2).toString();
            }
            // 获取表逻辑名（英文）
            Row row2 = sheet.getRow(2);
            String tableLogicName = null;
            if (row2.getCell(2)!= null) {
                tableLogicName = getCellValue(row2,2).toString();
            }

            // 获取描述（中文）
            Row row3 = sheet.getRow(3);
            String tableDesc = null;
            if (row3.getCell(2)!= null) {
                tableDesc = getCellValue(row3,2).toString();
            }

            if (StringUtils.isEmpty(tableName) || StringUtils.isEmpty(tableLogicName)) {
                throw new IOException("[" + sheet.getSheetName() + "]sheet无表名。");
            }

            ModelEntity me = new ModelEntity();
            me.setProjectId(projectId);
            me.setVersionId(0L);
            me.setEntityName(tableName);
            me.setEntityCode(tableLogicName);
            me.setRemark(tableDesc);
            me.setEntitySort(intEntitySort);
            me.setParentVersionId(0L);
            me.setCreateBy(ShiroUtils.getLoginName());
            me.setCreateTime(nowDate);
            me.setUpdateBy(ShiroUtils.getLoginName());
            me.setUpdateTime(nowDate);

            List<ModelField> mfs = new ArrayList<>();
            int rowIdx = 6;
            int sort = 1;
            while (StringUtils.isNotEmpty(getCellValue(sheet.getRow(rowIdx),1).toString()))
            {
                ModelField mf = new ModelField();

                // 字段名（中文）
                String fieldName = null;
                if (sheet.getRow(rowIdx).getCell(2) != null) {
                    fieldName = getCellValue(sheet.getRow(rowIdx),2).toString();
                };
                if (StringUtils.isEmpty(fieldName)) {
                    throw new IOException("[" + sheet.getSheetName() + "]sheet，第"+ (rowIdx + 1) + "行，字段名为空。");
                }

                // 逻辑名（英文）
                String fieldLogicName = null;
                if (sheet.getRow(rowIdx).getCell(3) != null) {
                    fieldLogicName = getCellValue(sheet.getRow(rowIdx),3).toString();
                };
                if (StringUtils.isEmpty(fieldLogicName)) {
                    throw new IOException("[" + sheet.getSheetName() + "]sheet，第"+ (rowIdx+1) + "行，逻辑名为空。");
                }
                // 类型（请选择）
                String fieldType = null;
                if (sheet.getRow(rowIdx).getCell(4) != null) {
                    fieldType = getCellValue(sheet.getRow(rowIdx),4).toString();
                };
                if (StringUtils.isEmpty(fieldType)) {
                    throw new IOException("[" + sheet.getSheetName() + "]sheet，第"+ (rowIdx+1) + "行，类型为空。");
                }
                // 主键（请选择）
                String fieldIsKey = null;
                if (sheet.getRow(rowIdx).getCell(5) != null) {
                    fieldIsKey = getCellValue(sheet.getRow(rowIdx), 5).toString();
                }
                if (StringUtils.isEmpty(fieldIsKey)) {
                    fieldIsKey = "N";
                }
                // 非空（请选择默认为N）
                String fieldNotNull = null;
                if (sheet.getRow(rowIdx).getCell(6) != null) {
                    fieldNotNull = getCellValue(sheet.getRow(rowIdx), 6).toString();
                }
                if (StringUtils.isEmpty(fieldNotNull)) {
                    fieldNotNull = "N";
                }
                // 自增（请选择默认为N）
                String fieldAuto = null;
                if (sheet.getRow(rowIdx).getCell(7) != null) {
                    fieldAuto = getCellValue(sheet.getRow(rowIdx), 7).toString();
                }
                if (StringUtils.isEmpty(fieldAuto)) {
                    fieldAuto = "N";
                }
                // 默认值
                String fieldDefaultValue = null;
                if (sheet.getRow(rowIdx).getCell(8) != null) {
                    fieldDefaultValue = getCellValue(sheet.getRow(rowIdx), 8).toString();
                }
                // 备注
                String fieldRemark = null;
                if (sheet.getRow(rowIdx).getCell(9) != null) {
                    fieldRemark = getCellValue(sheet.getRow(rowIdx), 9).toString();
                }

                mf.setProjectId(projectId);
                mf.setVersionId(0L);
                mf.setFieldName(fieldName);
                mf.setFieldCode(fieldLogicName);
                mf.setFieldType(fieldType);
                mf.setFieldPk(fieldIsKey);
                mf.setNotNull(fieldNotNull);
                mf.setAutoIncrement(fieldAuto);
                mf.setDefaultValue(fieldDefaultValue);
                mf.setFieldSort(sort);
                mf.setRemark(fieldRemark);
                mf.setParentVersionId(0L);
                mf.setCreateBy(ShiroUtils.getLoginName());
                mf.setCreateTime(nowDate);
                mf.setUpdateBy(ShiroUtils.getLoginName());
                mf.setUpdateTime(nowDate);

                mfs.add(mf);
                rowIdx = rowIdx +1;
                sort = sort + 1;
            }

            me.setFields(mfs);
            intEntitySort = intEntitySort + 1;
            mes.add(me);
        }

        for (ModelEntity modelEntity : mes) {
            rtn = rtn + modelEntityMapper.insertModelEntity(modelEntity);

            for (ModelField modelField : modelEntity.getFields()) {
                modelField.setEntityId(modelEntity.getId());
                rtn = rtn + modelFieldMapper.insertModelField(modelField);
            }
        }

        return rtn;
    }

    /**
     * 获取单元格值
     *
     * @param row 获取的行
     * @param column 获取单元格列号
     * @return 单元格值
     */
    public Object getCellValue(Row row, int column)
    {
        if (row == null)
        {
            return "";
        }
        Object val = "";
        try
        {
            Cell cell = row.getCell(column);
            if (StringUtils.isNotNull(cell))
            {
                if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA)
                {
                    val = cell.getNumericCellValue();
                    if (DateUtil.isCellDateFormatted(cell))
                    {
                        val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
                    }
                    else
                    {
                        if ((Double) val % 1 != 0)
                        {
                            val = new BigDecimal(val.toString());
                        }
                        else
                        {
                            val = new DecimalFormat("0").format(val);
                        }
                    }
                }
                else if (cell.getCellType() == CellType.STRING)
                {
                    val = cell.getStringCellValue();
                }
                else if (cell.getCellType() == CellType.BOOLEAN)
                {
                    val = cell.getBooleanCellValue();
                }
                else if (cell.getCellType() == CellType.ERROR)
                {
                    val = cell.getErrorCellValue();
                }

            }
        }
        catch (Exception e)
        {
            return val;
        }
        return val;
    }
}
