package ru.yandex.direct.web.entity.adgroup.controller;

import java.util.List;

import io.swagger.annotations.Api;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import ru.yandex.direct.core.entity.adgroup.container.UntypedAdGroup;
import ru.yandex.direct.core.entity.adgroup.model.CpmBannerAdGroup;
import ru.yandex.direct.core.entity.campaign.service.validation.CampaignAccessType;
import ru.yandex.direct.core.entity.retargeting.model.RetargetingCondition;
import ru.yandex.direct.core.entity.retargeting.model.TargetInterest;
import ru.yandex.direct.core.entity.user.model.User;
import ru.yandex.direct.dbutil.model.ClientId;
import ru.yandex.direct.result.MassResult;
import ru.yandex.direct.result.Result;
import ru.yandex.direct.validation.result.DefaultPathNodeConverterProvider;
import ru.yandex.direct.validation.result.PathNodeConverterProvider;
import ru.yandex.direct.web.core.model.WebResponse;
import ru.yandex.direct.web.core.security.DirectWebAuthenticationSource;
import ru.yandex.direct.web.entity.adgroup.model.SaveAdGroupsResponse;
import ru.yandex.direct.web.entity.adgroup.model.WebCpmAdGroup;
import ru.yandex.direct.web.entity.adgroup.presentations.AdGroupPathConverters;
import ru.yandex.direct.web.entity.adgroup.service.cpm.AddCpmAdGroupService;
import ru.yandex.direct.web.entity.adgroup.service.cpm.UpdateCpmAdGroupService;
import ru.yandex.direct.web.validation.kernel.ValidationResultConversionService;

import static ru.yandex.direct.core.validation.ValidationUtils.hasValidationIssues;
import static ru.yandex.direct.utils.FunctionalUtils.mapList;
import static ru.yandex.direct.web.core.security.authentication.DirectCookieAuthProvider.PARAMETER_ULOGIN;
import static ru.yandex.direct.web.entity.adgroup.presentations.AdGroupPathConverters.CPM_AD_GROUP_PATH_CONVERTER;

@RestController
@RequestMapping(path = "adgroups",
        consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
        produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@Api(tags = "adGroups")
public class CpmAdGroupController {

    private final ValidationResultConversionService validationResultConversionService;
    private final PathNodeConverterProvider pathNodeConverterProvider;
    private final DirectWebAuthenticationSource authenticationSource;
    private final AdGroupControllerHelper adGroupControllerHelper;

    private final AddCpmAdGroupService addCpmAdGroupService;
    private final UpdateCpmAdGroupService updateCpmAdGroupService;

    public CpmAdGroupController(
            AddCpmAdGroupService addCpmAdGroupService,
            UpdateCpmAdGroupService updateCpmAdGroupService,
            ValidationResultConversionService validationResultConversionService,
            PathNodeConverterProvider pathNodeConverterProvider,
            DirectWebAuthenticationSource authenticationSource,
            AdGroupControllerHelper adGroupControllerHelper) {
        this.addCpmAdGroupService = addCpmAdGroupService;
        this.updateCpmAdGroupService = updateCpmAdGroupService;
        this.validationResultConversionService = validationResultConversionService;
        this.authenticationSource = authenticationSource;

        this.pathNodeConverterProvider = DefaultPathNodeConverterProvider.builder()
                .register(UntypedAdGroup.class, CPM_AD_GROUP_PATH_CONVERTER)
                .register(CpmBannerAdGroup.class, CPM_AD_GROUP_PATH_CONVERTER)
                .register(RetargetingCondition.class, AdGroupPathConverters.CPM_AD_GROUP_RETARGETING_PATH_CONVERTER)
                .register(TargetInterest.class, AdGroupPathConverters.CPM_AD_GROUP_RETARGETING_PATH_CONVERTER)
                .fallbackTo(pathNodeConverterProvider)
                .build();
        this.adGroupControllerHelper = adGroupControllerHelper;
    }

    @SuppressWarnings("Duplicates")
    @RequestMapping(path = "/cpm/save", method = RequestMethod.POST)
    public WebResponse saveCpmAdGroup(
            @RequestBody List<WebCpmAdGroup> adGroups,
            @RequestParam(value = "campaign_id") Long campaignId,
            @RequestParam(value = "is_new_adgroups") Boolean isNewAdGroups,
            @RequestParam(value = "save_draft") Boolean saveDraft,
            @RequestParam(value = "is_copy") Boolean isCopy,
            @SuppressWarnings("unused") @RequestParam(value = PARAMETER_ULOGIN, required = false) String subjectLogin) {
        User operator = authenticationSource.getAuthentication().getOperator();
        User subjectUser = authenticationSource.getAuthentication().getSubjectUser();
        ClientId clientId = subjectUser.getClientId();
        long clientUid = subjectUser.getUid();
        long operatorUid = operator.getUid();

        adGroupControllerHelper.checkRequestParams(operatorUid, clientId, campaignId, CampaignAccessType.READ_WRITE);

        MassResult<Long> result;
        if (isNewAdGroups || isCopy) {
            result = addCpmAdGroupService
                    .addAdGroups(adGroups, campaignId, isCopy, saveDraft, operatorUid, clientId, clientUid);
        } else {
            result = updateCpmAdGroupService
                    .updateAdGroups(adGroups, campaignId, operatorUid, clientId, clientUid, saveDraft);
        }

        if (hasValidationIssues(result)) {
            return validationResultConversionService.buildValidationResponse(result.getValidationResult(),
                    pathNodeConverterProvider);
        } else {
            return new SaveAdGroupsResponse()
                    .withResult(mapList(result.getResult(), Result::getResult));
        }
    }
}
