package org.ruoyi.generator.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.core.page.PageQuery;
import org.ruoyi.core.page.TableDataInfo;
import org.ruoyi.generator.service.SchemaFieldService;
import org.ruoyi.generator.service.SchemaGroupService;
import org.ruoyi.generator.service.SchemaService;
import org.ruoyi.generator.domain.SchemaField;
import org.ruoyi.generator.domain.bo.SchemaFieldBo;
import org.ruoyi.generator.domain.vo.SchemaFieldVo;
import org.ruoyi.generator.domain.vo.SchemaGroupVo;
import org.ruoyi.generator.domain.vo.SchemaVo;
import org.ruoyi.generator.mapper.SchemaFieldMapper;
import org.ruoyi.helper.DataBaseHelper;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 数据模型字段Service业务层处理
 *
 * @author ruoyi
 */
@RequiredArgsConstructor
@Service
public class SchemaFieldServiceImpl implements SchemaFieldService {

    private final SchemaFieldMapper baseMapper;
    private final SchemaService schemaService;
    private final SchemaGroupService schemaGroupService;

    /**
     * 查询数据模型字段
     */
    @Override
    public SchemaFieldVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询数据模型字段列表
     */
    @Override
    public TableDataInfo<SchemaFieldVo> queryPageList(SchemaFieldBo bo, PageQuery pageQuery) {
        if (Objects.isNull(bo.getSchemaId())) {
            return TableDataInfo.build();
        }
        LambdaQueryWrapper<SchemaField> lqw = buildQueryWrapper(bo);
        Page<SchemaFieldVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    private LambdaQueryWrapper<SchemaField> buildQueryWrapper(SchemaFieldBo bo) {
        LambdaQueryWrapper<SchemaField> lqw = Wrappers.lambdaQuery();
        lqw.eq(SchemaField::getSchemaId, bo.getSchemaId());
        lqw.like(StringUtils.isNotBlank(bo.getName()), SchemaField::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getCode()), SchemaField::getCode, bo.getCode());
        lqw.eq(StringUtils.isNotBlank(bo.getType()), SchemaField::getType, bo.getType());
        lqw.eq(StringUtils.isNotBlank(bo.getIsPk()), SchemaField::getIsPk, bo.getIsPk());
        lqw.eq(StringUtils.isNotBlank(bo.getIsRequired()), SchemaField::getIsRequired, bo.getIsRequired());
        lqw.eq(StringUtils.isNotBlank(bo.getIsList()), SchemaField::getIsList, bo.getIsList());
        lqw.eq(StringUtils.isNotBlank(bo.getIsQuery()), SchemaField::getIsQuery, bo.getIsQuery());
        lqw.eq(StringUtils.isNotBlank(bo.getIsInsert()), SchemaField::getIsInsert, bo.getIsInsert());
        lqw.eq(StringUtils.isNotBlank(bo.getIsEdit()), SchemaField::getIsEdit, bo.getIsEdit());
        lqw.eq(StringUtils.isNotBlank(bo.getQueryType()), SchemaField::getQueryType, bo.getQueryType());
        lqw.eq(StringUtils.isNotBlank(bo.getHtmlType()), SchemaField::getHtmlType, bo.getHtmlType());
        lqw.like(StringUtils.isNotBlank(bo.getDictType()), SchemaField::getDictType, bo.getDictType());
        lqw.orderByAsc(SchemaField::getSort);
        return lqw;
    }

    /**
     * 新增数据模型字段
     */
    @Override
    public Boolean insertByBo(SchemaFieldBo bo) {
        SchemaField add = MapstructUtils.convert(bo, SchemaField.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改数据模型字段
     */
    @Override
    public Boolean updateByBo(SchemaFieldBo bo) {
        SchemaField update = MapstructUtils.convert(bo, SchemaField.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SchemaField entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除数据模型字段
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 批量更新字段配置
     */
    @Override
    public Boolean batchUpdateFieldConfig(List<SchemaFieldBo> fields) {
        if (fields == null || fields.isEmpty()) {
            return false;
        }

        for (SchemaFieldBo field : fields) {
            SchemaField update = MapstructUtils.convert(field, SchemaField.class);
            validEntityBeforeSave(update);
            baseMapper.updateById(update);
        }
        return true;
    }

    /**
     * 根据模型ID查询字段列表
     */
    @Override
    public List<SchemaFieldVo> queryListBySchemaId(Long schemaId) {
        LambdaQueryWrapper<SchemaField> lqw = Wrappers.lambdaQuery();
        lqw.eq(SchemaField::getSchemaId, schemaId);
        lqw.orderByAsc(SchemaField::getSort);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 根据表名称查询字段列表
     */
    @Override
    public List<SchemaFieldVo> queryListByTableName(String tableName) {
        // 先根据表名查询Schema
        SchemaVo schema = schemaService.queryByTableName(tableName);
        if (schema == null) {
            return new ArrayList<>();
        }
        // 再根据Schema ID查询字段列表
        return queryListBySchemaId(schema.getId());
    }

    @Override
    public Boolean deleteWithValidBySchemaIds(Collection<Long> schemaIds, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        // 先根据Schema ID查询字段列表
        LambdaQueryWrapper<SchemaField> queryWrapper = Wrappers.lambdaQuery(SchemaField.class);
        queryWrapper.in(SchemaField::getSchemaId, schemaIds);
        List<SchemaField> fields = baseMapper.selectList(queryWrapper);
        if (CollUtil.isEmpty(fields)) {
            return false;
        }
        // 再根据字段ID删除
        return deleteWithValidByIds(fields.stream().map(SchemaField::getId).collect(Collectors.toList()), false);
    }

    /**
     * 根据表名获取代码生成元数据
     */
    @Override
    public Object getMetaDataByTableName(String tableName) {
        // 根据表名查询Schema
        SchemaVo schema = schemaService.queryByTableName(tableName);
        if (schema == null) {
            return null;
        }
        SchemaGroupVo schemaGroupVo = schemaGroupService.queryById(schema.getSchemaGroupId());
        if (schemaGroupVo == null) {
            return null;
        }
        // 查询Schema对应的字段列表
        List<SchemaFieldVo> fields = queryListBySchemaId(schema.getId());
        if (CollUtil.isEmpty(fields)) {
            return null;
        }

        // 构建代码生成器需要的数据结构
        Map<String, Object> result = new HashMap<>();
        result.put("schemaGroupCode", schemaGroupVo.getCode());
        result.put("tableName", schema.getTableName());
        result.put("dictType",schema.getDictType());
        result.put("tableComment", schema.getComment());
        result.put("className", toCamelCase(schema.getTableName(), true));
        result.put("tableCamelName", StrUtil.toCamelCase(schema.getTableName()));
        result.put("functionName", schema.getName());
        result.put("schemaName", schema.getName());

        // 查找主键字段
        SchemaFieldVo pkField = fields.stream()
                .filter(field -> "1".equals(field.getIsPk()))
                .findFirst()
                .orElse(null);

        if (pkField != null) {
            Map<String, Object> pkColumn = new HashMap<>();
            pkColumn.put("columnName", pkField.getCode());
            pkColumn.put("dictType", pkField.getDictType());

            pkColumn.put("columnComment", pkField.getName());
            pkColumn.put("javaField", StrUtil.toCamelCase(pkField.getCode()));
            pkColumn.put("javaType", getJavaType(pkField.getType()));
            result.put("pkColumn", pkColumn);
        }

        // 构建字段列表
        List<Map<String, Object>> columns = new ArrayList<>();
        for (SchemaFieldVo field : fields) {
            Map<String, Object> column = new HashMap<>();
            column.put("columnName", field.getCode());
            column.put("dictType", field.getDictType());
            column.put("columnComment", field.getName());
            column.put("javaField", StrUtil.toCamelCase(field.getCode()));
            column.put("javaType", getJavaType(field.getType()));
            column.put("htmlType", field.getHtmlType());
            column.put("isPk", field.getIsPk());
            column.put("isRequired", field.getIsRequired());
            column.put("isInsert", field.getIsInsert());
            column.put("isEdit", field.getIsEdit());
            column.put("isList", field.getIsList());
            column.put("isQuery", field.getIsQuery());
            column.put("component", getComponentType(field.getHtmlType(), field.getQueryType()));
            column.put("queryType", field.getQueryType());
            column.put("remark", field.getRemark());
            columns.add(column);
        }
        result.put("columns", columns);

        return result;
    }

    @Override
    public boolean batchInsertFieldsByTableName(Long schemaId, String tableName) {
        try {
            // 获取表的字段信息
            List<Map<String, Object>> columnInfos = DataBaseHelper.getTableColumnInfo(tableName);
            if (CollUtil.isEmpty(columnInfos)) {
                return false;
            }
            LambdaQueryWrapper<SchemaField> lqw = Wrappers.lambdaQuery();
            lqw.eq(SchemaField::getSchemaId, schemaId);
            // 检查是否已存在字段数据
            List<SchemaFieldVo> existingFields = baseMapper.selectVoList(lqw);
            if (CollUtil.isNotEmpty(existingFields)) {
                // 如果已存在字段，则不重复插入
                return true;
            }
            // 转换为 SchemaField 对象并批量插入
            List<SchemaField> fieldsToInsert = new ArrayList<>();
            int sort = 1;
            for (Map<String, Object> columnInfo : columnInfos) {
                SchemaField field = new SchemaField();
                field.setSchemaId(schemaId);
                field.setSchemaName(tableName);
                field.setDefaultValue((String) columnInfo.get("columnDefault"));
                field.setComment((String) columnInfo.get("columnComment"));
                field.setName((String) columnInfo.get("columnComment"));
                field.setDictType(StrUtil.toCamelCase((String) columnInfo.get("dictType")));
                field.setCode(StrUtil.toCamelCase((String) columnInfo.get("columnName")));
                field.setType((String) columnInfo.get("dataType"));
                field.setLength(Integer.valueOf(String.valueOf(columnInfo.get("columnSize"))));
                field.setIsPk((Boolean) columnInfo.get("isPrimaryKey") ? "1" : "0");
                field.setIsRequired(!(Boolean) columnInfo.get("isNullable") ? "1" : "0");
                if ("1".equals(field.getIsPk())) {
                    field.setIsInsert("0");
                    field.setIsEdit("0");
                }else {
                    field.setIsInsert("1");
                    field.setIsEdit("1");
                }
                field.setIsList("1");
                field.setIsQuery("1");
                field.setQueryType("EQ");
                field.setHtmlType(getDefaultHtmlType((String) columnInfo.get("dataType")));
                field.setSort(sort++);
                // 如果字段名为空，使用字段代码作为名称
                if (StringUtils.isBlank(field.getName())) {
                    field.setName(field.getCode());
                }
                fieldsToInsert.add(field);
            }
            // 批量插入
            fieldsToInsert.forEach(baseMapper::insert);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据数据库类型获取默认的HTML类型
     */
    private String getDefaultHtmlType(String dbType) {
        if (StringUtils.isBlank(dbType)) {
            return "input";
        }

        String type = dbType.toLowerCase();
        if (type.contains("text") || type.contains("longtext")) {
            return "textarea";
        } else if ("datetime".equals(type) || "timestamp".equals(type)) {
            return "datetime";
        } else if ("date".equals(type)) {
            return "date";
        } else if ("time".equals(type)) {
            return "time";
        } else if (type.contains("bit") || type.contains("boolean")) {
            return "radio";
        } else {
            return "input";
        }
    }

    /**
     * 转换为驼峰命名
     */
    private String toCamelCase(String str, boolean firstUpperCase) {
        if (StringUtils.isBlank(str)) {
            return str;
        }

        StringBuilder result = new StringBuilder();
        String[] parts = str.split("_");
        for (int i = 0; i < parts.length; i++) {
            String part = parts[i].toLowerCase();
            if (i == 0 && !firstUpperCase) {
                result.append(part);
            } else {
                result.append(part.substring(0, 1).toUpperCase()).append(part.substring(1));
            }
        }
        return result.toString();
    }

    /**
     * 获取Java类型
     */
    private String getJavaType(String dbType) {
        if (StringUtils.isBlank(dbType)) {
            return "String";
        }

        String type = dbType.toLowerCase();
        if (StrUtil.equalsAny(type, "int", "tinyint", "smallint")) {
            return "Integer";
        } else if (StrUtil.equalsAny(type, "bigint")) {
            return "Long";
        } else if (StrUtil.equalsAny(type, "decimal", "numeric", "float", "double")) {
            return "BigDecimal";
        } else if (StrUtil.equalsAny(type, "date", "datetime","timestamp")) {
            return "Date";
        } else if (StrUtil.equalsAny(type, "bit", "boolean")) {
            return "Boolean";
        } else {
            return "String";
        }
    }

    /**
     * 获取组件类型
     */
    private String getComponentType(String htmlType, String queryType) {
        if (StringUtils.isBlank(htmlType)) {
            return "Input";
        }

        // 如果是范围查询且为日期时间类型，使用 RangePicker
        if ("BETWEEN".equals(queryType) &&
                ("datetime".equals(htmlType) || "date".equals(htmlType) || "time".equals(htmlType))) {
            return "RangePicker";
        }

        return switch (htmlType) {
            case "textarea" -> "Textarea";
            case "select" -> "Select";
            case "radio" -> "RadioGroup";
            case "checkbox" -> "CheckboxGroup";
            case "datetime", "date" -> "DatePicker";
            case "time" -> "TimePicker";
            case "imageUpload" -> "ImageUpload";
            case "fileUpload" -> "FileUpload";
            case "editor" -> "Editor";
            default -> "Input";
        };
    }


}