package tech.easyflow.datacenter.connector.support;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.row.RowKey;
import org.springframework.util.CollectionUtils;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.datacenter.connector.DatacenterConnector;
import tech.easyflow.datacenter.entity.DatacenterTable;
import tech.easyflow.datacenter.entity.DatacenterTableField;
import tech.easyflow.datacenter.execution.model.DatacenterConnectionTestResult;
import tech.easyflow.datacenter.execution.model.DatacenterQueryRequest;
import tech.easyflow.datacenter.meta.entity.DatacenterSource;
import tech.easyflow.datacenter.meta.enums.DatacenterCapability;
import tech.easyflow.datacenter.meta.enums.DatacenterSourceType;
import tech.easyflow.datacenter.meta.model.DatacenterCatalogMeta;
import tech.easyflow.datacenter.meta.model.DatacenterTableDetailMeta;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public abstract class AbstractInternalTableConnector implements DatacenterConnector {

    private final DatacenterSourceType sourceType;
    private final Set<DatacenterCapability> capabilities;

    protected AbstractInternalTableConnector(DatacenterSourceType sourceType, Set<DatacenterCapability> capabilities) {
        this.sourceType = sourceType;
        this.capabilities = capabilities;
    }

    @Override
    public DatacenterSourceType getSourceType() {
        return sourceType;
    }

    @Override
    public Set<DatacenterCapability> getCapabilities() {
        return capabilities;
    }

    @Override
    public DatacenterConnectionTestResult testConnection(DatacenterSource source) {
        DatacenterConnectionTestResult result = new DatacenterConnectionTestResult();
        result.setSuccess(true);
        result.setMessage("连接成功");
        result.setCapabilities(capabilities.stream().map(Enum::name).toList());
        result.setDetails(Map.of("sourceType", sourceType.name()));
        return result;
    }

    @Override
    public List<DatacenterCatalogMeta> listCatalogs(DatacenterSource source) {
        return Collections.emptyList();
    }

    @Override
    public List<DatacenterTable> listTables(DatacenterSource source, String catalogName) {
        return Collections.emptyList();
    }

    @Override
    public DatacenterTableDetailMeta getTableDetail(DatacenterSource source, String catalogName, String tableName) {
        throw new BusinessException("内部数据源请从元数据注册表读取表结构");
    }

    @Override
    public Page<Row> queryPage(DatacenterSource source, DatacenterTable table, DatacenterQueryRequest request) {
        String actualTable = resolveTableName(table);
        QueryWrapper wrapper = QueryWrapper.create();
        if (StrUtil.isNotBlank(request.getWhere())) {
            wrapper.where(request.getWhere());
        }
        long count = Db.selectCountByQuery(actualTable, wrapper);
        if (count == 0) {
            return new Page<>(new ArrayList<>(), request.getPageNumber(), request.getPageSize(), count);
        }
        Page<Row> page = Db.paginate(actualTable, new Page<>(request.getPageNumber(), request.getPageSize(), count), wrapper);
        normalizeRows(page.getRecords());
        return page;
    }

    @Override
    public List<Row> queryBySql(DatacenterSource source, String sql) {
        List<Row> rows = Db.selectListBySql(sql);
        normalizeRows(rows);
        return rows;
    }

    @Override
    public void saveRow(DatacenterSource source, DatacenterTable table, JSONObject data, LoginAccount account) {
        List<DatacenterTableField> fields = table.getFields();
        if (CollectionUtils.isEmpty(fields)) {
            throw new BusinessException("数据集字段为空，无法写入");
        }
        String actualTable = resolveTableName(table);
        Object id = data.get("id");
        if (id == null) {
            Row row = Row.ofKey(RowKey.SNOW_FLAKE_ID);
            row.put("dept_id", account.getDeptId());
            row.put("tenant_id", account.getTenantId());
            row.put("created", new Date());
            row.put("created_by", account.getId());
            row.put("modified", new Date());
            row.put("modified_by", account.getId());
            row.put("remark", data.get("remark"));
            for (DatacenterTableField field : fields) {
                row.put(field.getFieldName(), data.get(field.getFieldName()));
            }
            Db.insert(actualTable, row);
            return;
        }
        Row row = Row.ofKey("id", id);
        row.put("modified", new Date());
        row.put("modified_by", account.getId());
        for (DatacenterTableField field : fields) {
            row.put(field.getFieldName(), data.get(field.getFieldName()));
        }
        Db.updateById(actualTable, row);
    }

    @Override
    public void deleteRow(DatacenterSource source, DatacenterTable table, BigInteger id, LoginAccount account) {
        Db.deleteById(resolveTableName(table), Row.ofKey("id", id));
    }

    protected String resolveTableName(DatacenterTable table) {
        return StrUtil.blankToDefault(table.getMaterializedTable(), table.getActualTable());
    }

    private void normalizeRows(List<Row> records) {
        for (Row record : records) {
            Map<String, Object> converted = new LinkedHashMap<>();
            for (Map.Entry<String, Object> entry : record.entrySet()) {
                Object value = entry.getValue();
                if (value instanceof BigInteger || value instanceof BigDecimal || value instanceof Long) {
                    converted.put(entry.getKey(), value.toString());
                } else {
                    converted.put(entry.getKey(), value);
                }
            }
            record.clear();
            record.putAll(converted);
        }
    }
}
