package ru.yandex.autotests.directapi.darkside.model;

import java.io.UncheckedIOException;
import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.MoreObjects;
import one.util.streamex.StreamEx;

import ru.yandex.autotests.directapi.darkside.model.multipliers.BsAtom;
import ru.yandex.autotests.directapi.darkside.model.multipliers.DirectAtom;
import ru.yandex.autotests.directapi.darkside.model.multipliers.DirectAtomRaw;
import ru.yandex.autotests.directapi.darkside.model.multipliers.ExpressionParameter;
import ru.yandex.autotests.directapi.darkside.model.multipliers.ExpressionParameterType;
import ru.yandex.autotests.directapi.darkside.model.multipliers.Operation;
import ru.yandex.autotests.directapi.darkside.model.multipliers.SocdemValueAge;
import ru.yandex.autotests.directapi.darkside.model.multipliers.SocdemValueGender;

import static java.util.stream.Collectors.toList;

public class BidMultiplierUtils {
    public static DirectAtom directAtom(ExpressionParameter keyword, Operation operation, String value) {
        return new DirectAtom(keyword.getDirectValue(), operation.getDirectValue(), value);
    }

    public static BsAtom bsAtom(ExpressionParameter keyword, Operation operation, Integer value) {
        return new BsAtom(keyword.getBsValue(), operation.getBsValue(), value);
    }

    public static BsAtom bsAtom(ExpressionParameter keyword, Operation operation, String value) {
        return new BsAtom(keyword.getBsValue(), operation.getBsValue(), value);
    }

    public static DirectAtom socdemBsAtomAge(SocdemValueAge age) {
        return bsAtom(ExpressionParameter.AGE, Operation.eq, age.getBsValue());
    }

    public static DirectAtom socdemBsAtomGender(SocdemValueGender gender) {
        return bsAtom(ExpressionParameter.GENDER, Operation.eq, gender.getBsValue());
    }

    public static DirectAtom retargetingBsAtomContext(String retargetingId) {
        return bsAtom(ExpressionParameter.CONTEXT_ID, Operation.goalMatch, retargetingId);
    }

    public static DirectAtom geoBsAtomRegion(String regionId) {
        return bsAtom(ExpressionParameter.REGION_ID, Operation.eq, regionId);
    }

    public static List<List<DirectAtom>> convertExpressionAtoms(List<List<DirectAtom>> directExpression) {
        return StreamEx.of(directExpression)
                .map(orArray -> StreamEx.of(orArray)
                        .map(BidMultiplierUtils::convertToBsValues)
                        .map(t -> (DirectAtom) t)
                        .toList())
                .toList();
    }

    /**
     * преобразует значения операции из формата Директа в формат БК
     *
     * @param atom - элементарная логическая операция
     */
    private static BsAtom convertToBsValues(DirectAtom atom) {
        ExpressionParameterType type = ExpressionParameter.fromBsValue(atom.getKeyword()).getType();
        switch (type) {
            case INTEGER:
                return bsAtom(
                        ExpressionParameter.fromBsValue(atom.getKeyword()),
                        Operation.valueOf(atom.getOperation()),
                        atom.getValueInteger());
            case STRING:
                return bsAtom(
                        ExpressionParameter.fromBsValue(atom.getKeyword()),
                        Operation.valueOf(atom.getOperation()),
                        atom.getValueString());
            default: {
                throw new AssertionError("unknown type");
            }
        }
    }

    public static String serializeToDirectFormat(List<List<DirectAtom>> condition) {
        List<List<DirectAtomRaw>> rawCondition = condition.stream()
                .map(inner -> inner.stream().map(atom -> {
                    DirectAtomRaw atomRaw = new DirectAtomRaw();
                    atomRaw.setParameter(atom.getKeyword());
                    atomRaw.setOperation(atom.getOperation());
                    atomRaw.setValue(MoreObjects.firstNonNull(atom.getValueInteger(), atom.getValueString()));
                    return atomRaw;
                }).collect(toList()))
                .collect(toList());
        try {
            return new ObjectMapper().writeValueAsString(rawCondition);
        } catch (JsonProcessingException e) {
            throw new UncheckedIOException(e);
        }
    }
}
