package org.apache.seatunnel.transform.conversion;

import com.google.auto.service.AutoService;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.seatunnel.api.configuration.ReadonlyConfig;
import org.apache.seatunnel.api.configuration.util.ConfigValidator;
import org.apache.seatunnel.api.table.catalog.CatalogTable;
import org.apache.seatunnel.api.table.catalog.Column;
import org.apache.seatunnel.api.table.type.BasicType;
import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
import org.apache.seatunnel.api.table.type.SeaTunnelRowType;
import org.apache.seatunnel.api.transform.SeaTunnelTransform;
import org.apache.seatunnel.shade.com.typesafe.config.Config;
import org.apache.seatunnel.transform.common.MultipleFieldOutputTransform;
import org.apache.seatunnel.transform.common.SeaTunnelRowAccessor;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@AutoService(SeaTunnelTransform.class)
@NoArgsConstructor
public class TypeConversionTransform extends MultipleFieldOutputTransform {

    private ReadonlyConfig config;

    private Map<String, Integer> inputFieldIndex;

    public TypeConversionTransform(@NonNull ReadonlyConfig config, @NonNull CatalogTable inputCatalogTable) {
        super(inputCatalogTable);
        this.config = config;
        initOutputFields(
                inputCatalogTable.getTableSchema().toPhysicalRowDataType(),
                this.config.get(TypeConversionTransformConfig.KEY_FILTER_FIELD));
    }

    @Override
    public String getPluginName() {
        return "TypeConversion";
    }

    @Override
    protected void setConfig(Config pluginConfig) {
        ConfigValidator.of(ReadonlyConfig.fromConfig(pluginConfig))
                .validate(new TypeConversionTransformFactory().optionRule());
        this.config = ReadonlyConfig.fromConfig(pluginConfig);
    }

    @Override
    protected void setInputRowType(SeaTunnelRowType inputRowType) {
        initOutputFields(inputRowType, config.get(TypeConversionTransformConfig.KEY_FILTER_FIELD));
    }

    @Override
    protected String[] getOutputFieldNames() {
        List<TypeConversionEntity> list = config.get(TypeConversionTransformConfig.KEY_FILTER_FIELD);
        return list.stream().map(TypeConversionEntity::getColumn).toArray(String[]::new);
    }

    @Override
    protected SeaTunnelDataType[] getOutputFieldDataTypes() {
        List<TypeConversionEntity> list = config.get(TypeConversionTransformConfig.KEY_FILTER_FIELD);
        return ConversionUtil.getTypes(list).stream().toArray(BasicType[]::new);
    }

    @Override
    protected Object[] getOutputFieldValues(SeaTunnelRowAccessor inputRow) {
        Object[] objects = new Object[inputFieldIndex.size()];
        List<TypeConversionEntity> list = config.get(TypeConversionTransformConfig.KEY_FILTER_FIELD);
        int i = 0;
        for (TypeConversionEntity conversion : list) {
            if (inputFieldIndex.get(conversion.getColumn()) == null || inputFieldIndex.get(conversion.getColumn()) < 0) {
                continue;
            }
            Object inputFieldValue = inputRow.getField(inputFieldIndex.get(conversion.getColumn()));
            Object result = ConversionUtil.conversion(inputFieldValue, conversion);
            objects[i] = result;
            i++;
        }
        return objects;
    }

    @Override
    protected Column[] getOutputColumns() {
        Column[] columnList = new Column[inputFieldIndex.size()];
        List<TypeConversionEntity> list = config.get(TypeConversionTransformConfig.KEY_FILTER_FIELD);
        for (int i = 0; i < list.size(); i++) {
            List<Column> columns = inputCatalogTable.getTableSchema().getColumns();
            int finalI = i;
            List<Column> collect =
                    columns.stream().filter(column ->
                                    column.getName().equals(list.get(finalI).getColumn()))
                            .collect(Collectors.toList());
            if (CollectionUtils.isEmpty(collect)) {
                throw new IllegalArgumentException(
                        "Cannot find ["
                                + list.get(finalI).getColumn()
                                + "] field in input catalog table");
            }
            TypeConversionEntity conversion = list.get(i);
//            if (ConversionUtil.getDataType(conversion) != null) {
                Column column = ConversionUtil.conversionValueType(conversion,collect);
//                = collect.get(0).copy(BasicType.STRING_TYPE);
                columnList[i] = column;
//            }
//            else {
//                columnList[i] = collect.get(0).copy();
//            }
        }
        return columnList;
    }

    private void initOutputFields(SeaTunnelRowType inputRowType, List<TypeConversionEntity> replaceFields) {
        inputFieldIndex = new HashMap<>();
        for (TypeConversionEntity repeatEntity : replaceFields) {
            if (inputRowType.indexOf(repeatEntity.getColumn()) > 0) {
                inputFieldIndex.put(repeatEntity.getColumn(), inputRowType.indexOf(repeatEntity.getColumn()));
            } else {
                throw new IllegalArgumentException(
                        "Cannot find [" + repeatEntity.getColumn() + "] field in input row type");
            }
        }
    }
}
