package com.caliverse.admin.Indicators.Indicatorsservice.aggregationservice;

import com.caliverse.admin.Indicators.Indicatordomain.IndicatorsLog;
import com.caliverse.admin.Indicators.Indicatorsservice.base.IndicatorsLogLoadServiceBase;
import com.caliverse.admin.global.common.constants.AdminConstants;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class IndicatorsItemLoadService extends IndicatorsLogLoadServiceBase {
    public IndicatorsItemLoadService(
            @Qualifier("mongoIndicatorTemplate") MongoTemplate mongoTemplate
    ) {
        super(mongoTemplate);
    }

    @Override
    public <T extends IndicatorsLog> List<T> getIndicatorsLogData(String startTime, String endTime, Class<T> clazz) {

        return getItemsLogData(startTime, endTime, "Acquire", clazz);
    }

    public <T extends IndicatorsLog> List<T> getItemsLogData(String startTime, String endTime, String deltaType, Class<T> clazz) {

        Criteria criteria = makeCriteria(startTime, endTime, "logDay");

        UnwindOperation unwindOperation = Aggregation.unwind("itemDetails");
        UnwindOperation unwindOperation2 = Aggregation.unwind("itemDetails.items");

        MatchOperation matchOp = Aggregation.match(
                Criteria.where("itemDetails.items.countDeltaType").is(deltaType)
        );

        AggregationOperation groupOp = context -> new Document("$group",
                new Document("_id", new Document("logDay", "$logDay")
                        .append("itemMID", "$itemDetails.items.itemMID")
                        .append("action", "$itemDetails.items.action")
                )
                        .append("actionCount", new Document("$sum", "$itemDetails.items.deltaCount"))
                        .append("itemName", new Document("$first", "$itemDetails.items.itemName"))
        );

        AggregationOperation groupOp2 = context -> new Document("$group",
                new Document("_id", new Document("logDay", "$_id.logDay")
                        .append("itemMID", "$_id.itemMID")
                )
                        .append("totalDeltaCount", new Document("$sum", "$actionCount"))
                        .append("itemName", new Document("$first", "$itemName"))
                        .append("actions", new Document("$push",
                                new Document("k", "$_id.action").append("v", "$actionCount")
                        ))
        );

        AddFieldsOperation addFieldsOp = Aggregation.addFields()
                .addField("actionSummary")
                .withValue(ArrayOperators.ArrayToObject.arrayToObject("$actions"))
                .build();

        AggregationOperation projectOp = context -> new Document("$project", new Document()
                .append("_id", 0)
                .append("logDay", "$_id.logDay")
                .append("itemId", "$_id.itemMID")
                .append("itemName", 1)
                .append("totalDeltaCount", 1)
                .append("actionSummary", 1)
        );

        List<AggregationOperation> operations = List.of(
                Aggregation.match(criteria),
                unwindOperation,
                unwindOperation2,
                matchOp,
                groupOp,
                groupOp2,
                addFieldsOp,
                projectOp,
                Aggregation.sort(Sort.Direction.ASC, AdminConstants.MONGO_DB_KEY_LOGDAY)
        );

        Aggregation aggregation = Aggregation.newAggregation(operations);

        return mongoTemplate.aggregate(
                aggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build())
                , AdminConstants.MONGO_DB_COLLECTION_ITEM
                , clazz
        ).getMappedResults();
    }
}
