package tech.easyflow.datacenter.connector.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.row.Row;
import org.springframework.stereotype.Component;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.datacenter.connector.dialect.MysqlSqlDialect;
import tech.easyflow.datacenter.connector.support.AbstractJdbcConnector;
import tech.easyflow.datacenter.entity.DatacenterTable;
import tech.easyflow.datacenter.entity.DatacenterTableField;
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 javax.sql.DataSource;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class ProjectMysqlConnector extends AbstractJdbcConnector {

    private final DataSource dataSource;
    private final MysqlSqlDialect dialect = new MysqlSqlDialect();

    public ProjectMysqlConnector(DataSource dataSource) {
        super(DatacenterSourceType.PROJECT_MYSQL, new MysqlSqlDialect(), EnumSet.of(
                DatacenterCapability.TEST_CONNECTION,
                DatacenterCapability.BROWSE_METADATA,
                DatacenterCapability.READ_QUERY,
                DatacenterCapability.WRITE_MUTATION
        ));
        this.dataSource = dataSource;
    }

    @Override
    protected <T> T withConnection(DatacenterSource source, boolean cacheable, JdbcCallback<T> callback) throws Exception {
        try (Connection connection = dataSource.getConnection()) {
            return callback.apply(connection);
        }
    }

    @Override
    protected boolean requiresJdbcUrl() {
        return false;
    }

    @Override
    public Page<Row> queryPage(DatacenterSource source, DatacenterTable table, DatacenterQueryRequest request) {
        return super.queryPage(source, table, request);
    }

    @Override
    public void saveRow(DatacenterSource source, DatacenterTable table, JSONObject data, LoginAccount account) {
        List<DatacenterTableField> writableFields = table.getFields().stream()
                .filter(field -> field.getWritable() == null || field.getWritable() == 1)
                .collect(Collectors.toList());
        Object id = data.get("id");
        try (Connection connection = dataSource.getConnection()) {
            if (id == null) {
                List<String> columns = new ArrayList<>();
                List<Object> values = new ArrayList<>();
                for (DatacenterTableField field : writableFields) {
                    Object value = data.get(field.getFieldName());
                    if (value != null) {
                        columns.add(field.getFieldName());
                        values.add(value);
                    }
                }
                if (columns.isEmpty()) {
                    throw new BusinessException("没有可写字段");
                }
                String sql = "INSERT INTO " + dialect.qualifyTable(source.getDatabaseName(), resolvePhysicalTableName(table))
                        + " (" + columns.stream().map(dialect::quoteIdentifier).collect(Collectors.joining(",")) + ") VALUES ("
                        + columns.stream().map(item -> "?").collect(Collectors.joining(",")) + ")";
                try (PreparedStatement statement = connection.prepareStatement(sql)) {
                    for (int i = 0; i < values.size(); i++) {
                        statement.setObject(i + 1, values.get(i));
                    }
                    statement.executeUpdate();
                }
                return;
            }
            List<String> setClauses = new ArrayList<>();
            List<Object> values = new ArrayList<>();
            for (DatacenterTableField field : writableFields) {
                if (!data.containsKey(field.getFieldName())) {
                    continue;
                }
                setClauses.add(dialect.quoteIdentifier(field.getFieldName()) + " = ?");
                values.add(data.get(field.getFieldName()));
            }
            if (setClauses.isEmpty()) {
                return;
            }
            String sql = "UPDATE " + dialect.qualifyTable(source.getDatabaseName(), resolvePhysicalTableName(table))
                    + " SET " + String.join(",", setClauses)
                    + " WHERE " + dialect.quoteIdentifier("id") + " = ?";
            values.add(id);
            try (PreparedStatement statement = connection.prepareStatement(sql)) {
                for (int i = 0; i < values.size(); i++) {
                    statement.setObject(i + 1, values.get(i));
                }
                statement.executeUpdate();
            }
        } catch (Exception ex) {
            throw new BusinessException("项目 MySQL 写入失败: " + ex.getMessage());
        }
    }

    @Override
    public void deleteRow(DatacenterSource source, DatacenterTable table, BigInteger id, LoginAccount account) {
        String sql = "DELETE FROM " + dialect.qualifyTable(source.getDatabaseName(), resolvePhysicalTableName(table))
                + " WHERE " + dialect.quoteIdentifier("id") + " = ?";
        try (Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(sql)) {
            statement.setObject(1, id);
            statement.executeUpdate();
        } catch (Exception ex) {
            throw new BusinessException("项目 MySQL 删除失败: " + ex.getMessage());
        }
    }

    @Override
    protected String resolveCatalogName(DatacenterSource source, String requestedCatalogName) {
        return StrUtil.blankToDefault(requestedCatalogName, source.getDatabaseName());
    }
}
