package org.apache.seatunnel.transform.conversion;

import org.apache.commons.lang3.StringUtils;
import org.apache.seatunnel.api.table.catalog.Column;
import org.apache.seatunnel.api.table.type.BasicType;

import java.text.DecimalFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class ConversionUtil {

    public static Object conversion(Object value, TypeConversionEntity conversion) {
        String type = conversion.getConversionType();
        String dateFormat = conversion.getDataFormat();
        Boolean isDate = conversion.getIsDate();
        if (value == null || value.equals("null") || value.equals("")) {
            return "null";
        }
        switch (type.toLowerCase()) {
            case ValueType.INT:
                if(value.toString().equalsIgnoreCase("true")){
                    return 1;
                }else if(value.toString().equalsIgnoreCase("false")){
                    return 0;
                }else if (!isDate && StringUtils.isNoneEmpty(dateFormat)) {
                    String formatValue = formatData(value, dateFormat);
                    return new Double(formatValue).intValue();
                }
                return new Double(value.toString()).intValue();
            case ValueType.STRING:
                if (!isDate && StringUtils.isNoneEmpty(dateFormat)) {
                    if (dateFormat.contains("percent")) {
                        return formatData(value, dateFormat) + "%";
                    } else {
                        return formatData(value, dateFormat);
                    }
                }
                return String.valueOf(value);
            case ValueType.LONG:
            case ValueType.BIGINT:
                if (!isDate && StringUtils.isNoneEmpty(dateFormat)) {
                    String formatValue = formatData(value, dateFormat);
                    return Long.valueOf(formatValue);
                }
                return Long.valueOf(value.toString());
            case ValueType.FLOAT:
                if (!isDate && StringUtils.isNoneEmpty(dateFormat)) {
                    String formatValue = formatData(value, dateFormat);
                    return Float.valueOf(formatValue);
                }
                return Float.valueOf(value.toString());
            case ValueType.DOUBLE:
                if (!isDate && StringUtils.isNoneEmpty(dateFormat)) {
                    String formatValue = formatData(value, dateFormat);
                    return Double.valueOf(formatValue);
                }
                return Double.valueOf(value.toString());
            case ValueType.TIME:
            case ValueType.TIMESTAMP:
            case ValueType.DATE:
                if (isDate && StringUtils.isNoneEmpty(dateFormat)) {
                    return formatDate(value, dateFormat);
                }
                return value;
            default:
                return value.toString();
        }
    }

    public static List<BasicType> getTypes(List<TypeConversionEntity> list) {
        List<BasicType> basicTypes = new ArrayList<>();
        for (TypeConversionEntity conversion : list) {
            String type = conversion.getConversionType();
            switch (type.toLowerCase()) {
                case ValueType.INT:
                    basicTypes.add(BasicType.INT_TYPE);
                    break;
                case ValueType.BIGINT:
                case ValueType.LONG:
                    basicTypes.add(BasicType.LONG_TYPE);
                    break;
                case ValueType.FLOAT:
                    basicTypes.add(BasicType.FLOAT_TYPE);
                    break;
                case ValueType.DOUBLE:
                    basicTypes.add(BasicType.DOUBLE_TYPE);
                    break;
                case ValueType.BOOLEAN:
                    basicTypes.add(BasicType.BOOLEAN_TYPE);
                    break;
                default:
                    basicTypes.add(BasicType.STRING_TYPE);
                    break;
            }
        }

        return basicTypes;
    }

    public static BasicType getDataType(TypeConversionEntity conversion) {
        String type = conversion.getConversionType();
        if (StringUtils.isEmpty(type)) {
            return null;
        }
        switch (type.toLowerCase()) {
            case ValueType.INT:
                return BasicType.INT_TYPE;
            case ValueType.BIGINT:
                return BasicType.DOUBLE_TYPE;
            case ValueType.LONG:
                return BasicType.LONG_TYPE;
            case ValueType.FLOAT:
                return BasicType.FLOAT_TYPE;
            case ValueType.BOOLEAN:
                return BasicType.BOOLEAN_TYPE;
            default:
                return BasicType.STRING_TYPE;
        }
    }

    /**
     * 格式化数据
     */
    private static String formatData(Object value, String dateFormat) {
        DecimalFormat df = null;
        switch (dateFormat) {
            case DataFormat.INTEGER:
                df = new DecimalFormat("#");
                return df.format(value);
            case DataFormat.POINT_ONE:
                df = new DecimalFormat("#.0");
                return df.format(value);
            case DataFormat.POINT_TOW:
                df = new DecimalFormat("#.00");
                return df.format(value);
            case DataFormat.PERCENT:
                double num = Double.parseDouble(value.toString()) * 100;
                return Double.toString(num);
            case DataFormat.PERCENT_POINT_ONE:
                df = new DecimalFormat("#.0");
                double pointOne = Double.parseDouble(value.toString()) * 100;
                return df.format(pointOne);
            case DataFormat.PERCENT_POINT_TWO:
                df = new DecimalFormat("#.00");
                double pointTwo = Double.parseDouble(value.toString()) * 100;
                return df.format(pointTwo);
            default:
                return value.toString();
        }
    }

    private static String formatDate(Object value, String dateFormat) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime date = null;
        if (value instanceof LocalDateTime) {
            date = (LocalDateTime) value;
        } else if (value instanceof Date) {
            Date dates = (Date) value;
            Instant instant = dates.toInstant();
            ZoneId zoneId = ZoneId.systemDefault();
            date = instant.atZone(zoneId).toLocalDateTime();
        } else if (value instanceof LocalDate) {
            LocalDate dates = (LocalDate) value;
            date = dates.atStartOfDay();
        } else if (value instanceof String) {
            try{
                date = LocalDateTime.parse(value.toString(), fmt);
            }catch (Exception e){//兼容行堆叠之后所有字段变成字符串问题
                date = LocalDateTime.parse(value.toString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            }
        }
        if (date == null) {
            return null;
        }
        switch (dateFormat) {
            case DataFormat.YYYY:
                return String.valueOf(date.getYear());
            case DataFormat.YYYYMM:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.YYYYMM));
//                return  date.getYear()+ String.valueOf(date.getMonthValue());
            case DataFormat.YYYY_MM:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.YYYY_MM));
//                return date.getYear()+ "-" + date.getMonthValue();
            case DataFormat.YYYYMMS:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.YYYYMMS));
//                return date.getYear()+ "/" + date.getMonthValue();
            case DataFormat.YYYYMMDD:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.YYYYMMDD));
            case DataFormat.YYYY_MM_DD:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.YYYY_MM_DD));
            case DataFormat.YYYYMMDDS:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.YYYYMMDDS));
            case DataFormat.YYYYMMDD_HHMMSS:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.YYYYMMDD_HHMMSS));
            case DataFormat.YYYY_MM_DD_HHMMSS:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.YYYY_MM_DD_HHMMSS));
            case DataFormat.YYYYMMDDS_HHMMSS:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.YYYYMMDDS_HHMMSS));
            case DataFormat.HH:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.HH));
//                return String.valueOf(date.getHour());
            case DataFormat.HH_MM:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.HH_MM));
//                return date.getHour() + ":" + date.getMinute();
            case DataFormat.HH_MM_SS:
                return date.format(DateTimeFormatter.ofPattern(DataFormat.HH_MM_SS));
//                return date.getHour() + ":" + date.getMinute() + ":" + date.getSecond();
            default:
                return value.toString();
        }
    }

    public static Column conversionValueType(TypeConversionEntity conversion, List<Column> collect) {
        String type = conversion.getConversionType();
        switch (type.toLowerCase()) {
            case ValueType.INT:
                return collect.get(0).copy(BasicType.INT_TYPE);
            case ValueType.STRING:
            case ValueType.DATE:
                return collect.get(0).copy(BasicType.STRING_TYPE);
            case ValueType.BIGINT:
            case ValueType.LONG:
                return collect.get(0).copy(BasicType.LONG_TYPE);
            case ValueType.FLOAT:
                return collect.get(0).copy(BasicType.FLOAT_TYPE);
            case ValueType.DOUBLE:
                return collect.get(0).copy(BasicType.DOUBLE_TYPE);
            default:
                return collect.get(0).copy();
        }
    }
}
