package ru.yandex.webmaster3.storage.util.ydb.querybuilder;


import java.util.Collection;
import java.util.Collections;
import java.util.function.Function;

import com.google.common.base.Strings;
import com.yandex.ydb.table.result.ResultSetReader;
import com.yandex.ydb.table.values.Type;
import lombok.RequiredArgsConstructor;

import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.AnyField;
import ru.yandex.webmaster3.storage.util.ydb.querybuilder.typesafe.Field;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * ishalaru
 * 11.08.2020
 **/
public class Utils {
    static class FCall {

        private final String alias;
        private final String name;
        private final Object[] parameters;

        FCall(String alias, String name, Object... parameters) {
            checkNotNull(name);
            this.name = name;
            this.parameters = parameters;
            this.alias = alias;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append(name).append('(');
            for (int i = 0; i < parameters.length; i++) {
                if (i > 0) {
                    sb.append(',');
                }
                sb.append(parameters[i]);
            }
            if (Strings.isNullOrEmpty(alias)) {
                sb.append(')');
            } else {
                sb.append(") as ").append(alias);
            }
            return sb.toString();
        }
    }

    static class CName {
        private final String name;

        CName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    static class Alias {
        private final Object column;
        private final String alias;

        Alias(Object column, String alias) {
            this.column = column;
            this.alias = alias;
        }

        @Override
        public String toString() {
            return String.format("%s AS %s", column, alias);
        }
    }

    static class Cast {
        private final Object column;
        private final Type targetType;

        Cast(Object column, Type targetType) {
            this.column = column;
            this.targetType = targetType;
        }

        @Override
        public String toString() {
            return String.format("CAST(%s AS %s)", column, targetType);
        }
    }


    @RequiredArgsConstructor
    static class FMapCall<T, R> implements AnyField<R> {
        private final String alias;
        private final String operation;
        private final Field<T> column;
        private final Function<ResultSetReader, R> mapper;

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append(operation).append('(').append(column);
            if (Strings.isNullOrEmpty(alias)) {
                sb.append(')');
            } else {
                sb.append(") as ").append(alias);
            }
            return sb.toString();
        }

        @Override
        public String getName() {
            return toString();
        }

        @Override
        public R asDBValue(R value) {
            return value;
        }

        @Override
        public Collection<String> getDependencyColumns() {
            return Collections.singleton(toString());
        }

        @Override
        public R get(ResultSetReader row) {
            return mapper.apply(row);
        }
    }
}
