/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.seatunnel.transform.condition;

import com.google.auto.service.AutoService;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.apache.seatunnel.api.configuration.ReadonlyConfig;
import org.apache.seatunnel.api.configuration.util.ConfigValidator;
import org.apache.seatunnel.api.table.catalog.*;
import org.apache.seatunnel.api.table.type.SeaTunnelDataType;
import org.apache.seatunnel.api.table.type.SeaTunnelRow;
import org.apache.seatunnel.api.table.type.SeaTunnelRowType;
import org.apache.seatunnel.api.table.type.SqlType;
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.utils.NumberUtil;


import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

@AutoService(SeaTunnelTransform.class)
@NoArgsConstructor
public class ConditionTransform extends MultipleFieldOutputTransform {
    public static String PLUGIN_NAME = "FieldCondition";
    private ConditionTransformConfig config;
    private static ConcurrentHashMap<String, DateTimeFormatter> dateTimeFormatterMap = new ConcurrentHashMap<>();

    public ConditionTransform(
            @NonNull ConditionTransformConfig config, @NonNull CatalogTable catalogTable) {
        super(catalogTable);
        this.config = config;
    }

    @Override
    public String getPluginName() {
        return PLUGIN_NAME;
    }

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

    @Override
    protected SeaTunnelRowType transformRowType(SeaTunnelRowType inputRowType) {
        return inputRowType;
    }


    @Override
    protected SeaTunnelRow transformRow(SeaTunnelRow inputRow) {
        List<ConditionEntity> fieldCondition = config.getFieldCondition();
        String connectType = config.getConnectType();
        List<Boolean>flagList=new ArrayList<>();
        fieldCondition.forEach(x->{
            boolean flag = false;
            String valueStr = String.valueOf(inputRow.getField(inputRowType.indexOf(x.getField())));
            //boolean number = NumberUtil.isNumber(valueStr);
            OperateType operateType = x.getOperateType();
            ConditionDataType dataType = x.getDataType();
            if (dataType == ConditionDataType.number){
                BigDecimal rowValue = new BigDecimal(valueStr);
                BigDecimal value = new BigDecimal(x.getValue().toString());
                flag = operateType.getNumberFunction().apply(rowValue, value);
            }else if(dataType == ConditionDataType.string) {
                flag = operateType.getStrFunction().apply(valueStr, x.getValue().toString());
            }else{
                String format = Optional.<String>of(x.getFormat()).orElse("yyyy-MM-dd");
                String value = x.getValue().toString();
                try {
                    DateTimeFormatter dtf = dateTimeFormatterMap.get(format);
                    if(dtf == null){
                        dtf = new DateTimeFormatterBuilder().appendPattern(format)
                                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                                .toFormatter();
                        dateTimeFormatterMap.put(format, dtf);
                    }
                    long rowDatetimeTs = LocalDateTime.parse(valueStr, dtf).toInstant(ZoneOffset.of("+8")).toEpochMilli();
                    long valueDatetimeTs = LocalDateTime.parse(value, dtf).toInstant(ZoneOffset.of("+8")).toEpochMilli();
                    flag = operateType.getNumberFunction().apply(BigDecimal.valueOf(rowDatetimeTs), BigDecimal.valueOf(valueDatetimeTs));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            flagList.add(flag);
        });
        //满足条件直接过滤掉该数据
        if((("AND".equalsIgnoreCase(connectType) || connectType == null || "".equals(connectType.trim())) && !flagList.contains(false))
                || ("OR".equalsIgnoreCase(connectType) && flagList.contains(true))){
            return inputRow;
        }
        return null;

    }

    @Override
    protected void setInputRowType(SeaTunnelRowType inputRowType) {

    }

    @Override
    protected String[] getOutputFieldNames() {
        return new String[0];
    }

    @Override
    protected SeaTunnelDataType[] getOutputFieldDataTypes() {
        return new SeaTunnelDataType[0];
    }

    @Override
    protected Object[] getOutputFieldValues(SeaTunnelRowAccessor inputRow) {
        return new Object[0];
    }

    @Override
    protected TableSchema transformTableSchema() {
        return null;
    }

    @Override
    protected TableIdentifier transformTableIdentifier() {
        return inputCatalogTable.getTableId().copy();
    }

    @Override
    protected Column[] getOutputColumns() {
        return new Column[0];
    }
}
