package io.delphi.qa.auto.awsmfrw.managers.helpers.db.bigTable;

import com.google.cloud.bigtable.data.v2.models.Row;
import com.google.cloud.bigtable.data.v2.models.RowCell;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import io.delphi.qa.auto.awsmfrw.common_baby.IsaCommonMethods;
import io.qameta.allure.Step;
import org.apache.commons.lang3.tuple.Pair;

import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BigTableClient extends HlBigTable implements IsaCommonMethods {


  public BigTableClient(Map<String, String> secretMap){
    super(secretMap);
  }
    @Step("DB:: Get Row from Bigtable")
    public <T> String getValueFromBigTable(String tableName, String rowKey, String valueName) {
        ByteBuffer value = this.fetchQueriedEntities(tableName, rowKey).getCells().stream()
                .filter(b -> b.getQualifier().equals(ByteString.copyFromUtf8(valueName)))
                .map(cell -> ByteBuffer.wrap(cell.getValue().toByteArray())).findAny().orElse(null);
        return value == null ? null : new String(value.array(), value.position(), value.remaining());
    }

    @Step("DB:: Get Row from Bigtable")
    public <T extends Message> T getValueFromBigTable(String tableName, String rowKey, String valueName, Class<T> valueType) {
        Row value = this.fetchQueriedEntities(tableName, rowKey);
        byte[] protobufData = null;

        if (value != null) {
            protobufData = value.getCells().stream()
                    .filter(b -> b.getQualifier().equals(ByteString.copyFromUtf8(valueName)))
                    .map(cell -> cell.getValue().toByteArray())
                    .findAny()
                    .orElse(null);
        }

        if (protobufData == null) {
            return null;
        } else if (Message.class.isAssignableFrom(valueType)) {
            try {
                Method parseFromMethod = valueType.getDeclaredMethod("parseFrom", byte[].class);
                return (T) parseFromMethod.invoke(null, protobufData);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        } else {
            throw new IllegalArgumentException("The provided class is not a Protobuf message type.");
        }
    }

    @Step("DB:: Get Map<Rows> from Bigtable")
    public <T> Map<String, T> getProtobufMapFromBigTable(String tableName, Pair<String, String> rowKeys, String keyQualifier, String valueQualifier, Class<T> valueType) {
        Map<String, T> resultMap = new HashMap<>();

        List<List<RowCell>> value = this.fetchRangeQueriedEntities(tableName, rowKeys);

        for (List<RowCell> row : value) {
            String keyFromRow = null;
            T valueFromRow = null;

            for (RowCell cell : row) {
                if (cell.getQualifier().toStringUtf8().equals(keyQualifier)) {
                    keyFromRow = cell.getValue().toStringUtf8();
                } else if (cell.getQualifier().toStringUtf8().equals(valueQualifier)) {
                    byte[] protobufData = cell.getValue().toByteArray();

                    try {
                        Method parseFromMethod = valueType.getDeclaredMethod("parseFrom", byte[].class);
                        valueFromRow = (T) parseFromMethod.invoke(null, protobufData);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                if (keyFromRow != null && valueFromRow != null) {
                    resultMap.put(keyFromRow, valueFromRow);
                    break;
                }
            }
        }

        return resultMap;
    }

    @Step("DB:: Get Upc Brand data from Bigtable")
    public List<Map<String, String>> getRowValuesFromBigTable(String tableName, Pair<String, String> rowKey, List<String> qualifiers) {
        List<List<RowCell>> value = this.fetchRangeQueriedEntities(tableName, rowKey);

        List<Map<String, String>> resultList = new ArrayList<>();

        for (List<RowCell> rowCells : value) {
            Map<String, String> map = new HashMap<>();

            for (String qualifier : qualifiers) {
                String valueForQualifier = rowCells.stream()
                        .filter(b -> b.getQualifier().equals(ByteString.copyFromUtf8(qualifier)))
                        .map(cell -> cell.getValue().toStringUtf8())
                        .findAny()
                        .orElse(null);

                map.put(qualifier, valueForQualifier);
            }

            resultList.add(map);
        }
        return resultList;
    }
}
