package org.apache.seatunnel.transform.replaces;

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 org.apache.seatunnel.transform.replace.ReplaceTransformConfig;
import org.apache.seatunnel.transform.replace.ReplaceTransformFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

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

    private ReadonlyConfig config;
    private List<Integer> inputFieldIndex;

    public ReplaceTransform(
            @NonNull ReadonlyConfig config, @NonNull CatalogTable inputCatalogTable) {
        super(inputCatalogTable);
        this.config = config;
        initOutputFields(
                inputCatalogTable.getTableSchema().toPhysicalRowDataType(),
                this.config.get(ReplaceTransformConfig.KEY_REPLACE_FIELD));
    }

    @Override
    public String getPluginName() {
        return "Replace-list";
    }

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

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

    @Override
    protected String[] getOutputFieldNames() {
        return config.get(ReplaceTransformConfig.KEY_REPLACE_FIELD).split(",");
    }

    @Override
    protected SeaTunnelDataType[] getOutputFieldDataTypes() {
        return new BasicType[]{BasicType.STRING_TYPE};
    }

    @Override
    protected Object[] getOutputFieldValues(SeaTunnelRowAccessor inputRow) {

        Object[] objects = new Object[inputFieldIndex.size()];
        for (int i = 0; i < inputFieldIndex.size(); i++) {
            Object inputFieldValue = inputRow.getField(inputFieldIndex.get(i));
            String[] replace = config.get(ReplaceTransformConfig.KEY_PATTERN).split(",");
            String[] isReplace = config.get(ReplaceTransformConfig.KEY_REPLACEMENT).split(",");

            if (inputFieldValue == null || inputFieldValue.equals("")) {
                inputFieldValue = "null";
            }

            boolean isRegex =
                    config.get(ReplaceTransformConfig.KEY_IS_REGEX) == null
                            ? false
                            : config.get(ReplaceTransformConfig.KEY_IS_REGEX);
            if (isRegex) {
                if (config.get(ReplaceTransformConfig.KEY_REPLACE_FIRST)) {
                    objects[i] = inputFieldValue
                            .toString()
                            .replaceFirst(
                                    replace.length > 1 ? replace[i] : replace[0],
                                    isReplace.length > 1 ? isReplace[i] : isReplace[0]);
                }
                objects[i] = inputFieldValue
                        .toString()
                        .replaceAll(
                                replace.length > 1 ? replace[i] : replace[0],
                                isReplace.length > 1 ? isReplace[i] : isReplace[0]);
            }
            objects[i] = inputFieldValue.toString()
                    .replace(
                            replace.length > 1 ? replace[i] : replace[0],
                            isReplace.length > 1 ? isReplace[i] : isReplace[0]);
        }

        return objects;
    }

    @Override
    protected Column[] getOutputColumns() {
        Column[] columnList = new Column[inputFieldIndex.size()];
        String[] splitColums = config.get(ReplaceTransformConfig.KEY_REPLACE_FIELD).split(",");
        for (int i = 0; i < splitColums.length; i++) {
            List<Column> columns = inputCatalogTable.getTableSchema().getColumns();
            int finalI = i;
            List<Column> collect =
                    columns.stream().filter(column ->
                            column.getName().equals(splitColums[finalI]))
                                    .collect(Collectors.toList());
            if (CollectionUtils.isEmpty(collect)) {
                throw new IllegalArgumentException(
                        "Cannot find ["
                                + splitColums[i]
                                + "] field in input catalog table");
            }
            columnList[i] = collect.get(0).copy();
        }

        return columnList;
    }

    private void initOutputFields(SeaTunnelRowType inputRowType, String replaceField) {
        inputFieldIndex = new ArrayList<>();
        for (String s : replaceField.split(",")) {
            inputFieldIndex.add(inputRowType.indexOf(s));
            if (CollectionUtils.isEmpty(inputFieldIndex)) {
                throw new IllegalArgumentException(
                        "Cannot find [" + replaceField + "] field in input row type");
            }
        }
    }
}
