package com.Modules.etl.handler;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/**
 * 字节数组类型处理器 - 达梦数据库兼容版本
 * 
 * 将 Java byte[][] 与数据库 TEXT 列进行互转。
 * 存储格式: JSON 数组字符串，每个元素为 Base64 编码，如 ["base64...","base64..."]
 * 空数组: 存储为 "[]"
 * null值: 存储为 NULL
 * 
 * 原 PostgreSQL 版本使用 createArrayOf("bytea", ...) 创建原生 bytea 数组，
 * 达梦数据库不兼容此 API，改为 TEXT 列存储 JSON 数组（Base64编码）。
 */
@MappedTypes(byte[][].class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ArrayByteTypeHandler extends BaseTypeHandler<byte[][]> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, byte[][] parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, toJsonArray(parameter));
    }

    @Override
    public byte[][] getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return parseJsonArray(rs.getString(columnName));
    }

    @Override
    public byte[][] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return parseJsonArray(rs.getString(columnIndex));
    }

    @Override
    public byte[][] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return parseJsonArray(cs.getString(columnIndex));
    }

    private byte[][] parseJsonArray(String value) {
        if (value == null || value.isEmpty() || "[]".equals(value.trim())) {
            return new byte[0][];
        }
        if (!value.startsWith("[")) {
            // 兼容旧的逗号分隔格式
            return parseCommaSeparated(value);
        }
        String content = value.substring(1, value.length() - 1).trim();
        if (content.isEmpty()) {
            return new byte[0][];
        }
        // 解析 JSON 字符串数组
        List<byte[]> result = new ArrayList<>();
        int pos = 0;
        int len = content.length();
        while (pos < len) {
            if (content.charAt(pos) == '"') {
                int end = pos + 1;
                while (end < len) {
                    if (content.charAt(end) == '"' && content.charAt(end - 1) != '\\') {
                        break;
                    }
                    end++;
                }
                String base64 = content.substring(pos + 1, end);
                if (!base64.isEmpty()) {
                    result.add(Base64.getDecoder().decode(base64));
                } else {
                    result.add(new byte[0]);
                }
                pos = end + 1;
                while (pos < len && (content.charAt(pos) == ',' || content.charAt(pos) == ' ')) {
                    pos++;
                }
            } else {
                // skip non-string content
                pos++;
            }
        }
        return result.toArray(new byte[0][]);
    }

    private byte[][] parseCommaSeparated(String value) {
        String[] parts = value.split(",", -1);
        byte[][] result = new byte[parts.length][];
        for (int i = 0; i < parts.length; i++) {
            String part = parts[i].trim();
            if (part.isEmpty()) {
                result[i] = new byte[0];
            } else {
                result[i] = Base64.getDecoder().decode(part);
            }
        }
        return result;
    }

    static String toJsonArray(byte[][] array) {
        if (array == null) {
            return null;
        }
        if (array.length == 0) {
            return "[]";
        }
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < array.length; i++) {
            if (i > 0) sb.append(",");
            sb.append("\"");
            if (array[i] != null && array[i].length > 0) {
                sb.append(Base64.getEncoder().encodeToString(array[i]));
            }
            sb.append("\"");
        }
        sb.append("]");
        return sb.toString();
    }
}
