package ru.yandex.direct.api.v5.entity.businesses.delegate;

import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

import com.yandex.direct.api.v5.businesses.BusinessFieldEnum;
import com.yandex.direct.api.v5.businesses.BusinessGetItem;
import com.yandex.direct.api.v5.businesses.GetRequest;
import com.yandex.direct.api.v5.businesses.GetResponse;
import com.yandex.direct.api.v5.general.IdsCriteria;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;

import ru.yandex.altay.model.language.LanguageOuterClass.Language;
import ru.yandex.direct.api.v5.common.ApiPathConverter;
import ru.yandex.direct.api.v5.common.EnumPropertyFilter;
import ru.yandex.direct.api.v5.entity.GenericGetRequest;
import ru.yandex.direct.api.v5.entity.GetApiServiceDelegate;
import ru.yandex.direct.api.v5.entity.businesses.converter.GetBusinessesResponseConverter;
import ru.yandex.direct.api.v5.entity.businesses.validation.GetBusinessesValidationService;
import ru.yandex.direct.api.v5.security.ApiAuthenticationSource;
import ru.yandex.direct.api.v5.validation.DefectType;
import ru.yandex.direct.common.util.PropertyFilter;
import ru.yandex.direct.core.entity.organizations.service.OrganizationService;
import ru.yandex.direct.dbutil.model.ClientId;
import ru.yandex.direct.organizations.swagger.OrganizationApiInfo;
import ru.yandex.direct.validation.result.ValidationResult;

import static ru.yandex.direct.organizations.swagger.OrganizationsClient.getLanguageByName;
import static ru.yandex.direct.utils.FunctionalUtils.mapList;

@Component
@ParametersAreNonnullByDefault
public class GetBusinessesDelegate
        extends GetApiServiceDelegate<GetRequest, GetResponse, BusinessFieldEnum, List<Long>, OrganizationApiInfo> {

    private static final Logger logger = LoggerFactory.getLogger(GetBusinessesDelegate.class);

    private final OrganizationService organizationService;
    private final EnumPropertyFilter<BusinessFieldEnum> propertyFilter;

    @Autowired
    public GetBusinessesDelegate(ApiAuthenticationSource auth,
                                 OrganizationService organizationService,
                                 PropertyFilter propertyFilter) {
        super(ApiPathConverter.forBusinesses(), auth);
        this.organizationService = organizationService;
        this.propertyFilter = EnumPropertyFilter.from(BusinessFieldEnum.class, propertyFilter);
    }

    @Nullable
    @Override
    public ValidationResult<GetRequest, DefectType> validateRequest(GetRequest externalRequest) {
        return GetBusinessesValidationService.validateRequest(externalRequest);
    }

    @Override
    public Set<BusinessFieldEnum> extractFieldNames(GetRequest externalRequest) {
        return Set.copyOf(externalRequest.getFieldNames());
    }

    @Override
    public List<Long> extractSelectionCriteria(GetRequest externalRequest) {
        IdsCriteria selectionCriteria = externalRequest.getSelectionCriteria();
        return selectionCriteria != null && selectionCriteria.getIds() != null && !selectionCriteria.getIds().isEmpty()
                ? selectionCriteria.getIds()
                : null;
    }

    @Override
    public List<OrganizationApiInfo> get(GenericGetRequest<BusinessFieldEnum, List<Long>> getRequest) {
        List<Long> ids = getRequest.getSelectionCriteria();
        logger.debug("Get permalinks: ids {}", ids);

        long chiefUid = auth.getChiefSubclient().getChiefUid();
        ClientId clientId = auth.getChiefSubclient().getClientId();
        Language language = getLanguageByName(LocaleContextHolder.getLocale().getLanguage()).orElse(Language.EN);
        return organizationService.getApiClientOrganizationsWithoutMetrikaData(clientId, chiefUid, language, ids);
    }

    @Override
    public GetResponse convertGetResponse(List<OrganizationApiInfo> result, Set<BusinessFieldEnum> requestedFields,
                                          @Nullable Long limitedBy) {
        logger.debug("Convert response: result {}, requestedFields {}, limitedBy {}",
                result, requestedFields, limitedBy);

        List<BusinessGetItem> getItems = mapList(result, GetBusinessesResponseConverter::convert);
        propertyFilter.filterProperties(getItems, requestedFields);

        return new GetResponse()
                .withLimitedBy(limitedBy)
                .withBusinesses(getItems);
    }
}
