package ru.yandex.direct.api.v5.security;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import ru.yandex.direct.core.entity.campaign.model.RequestSource;
import ru.yandex.direct.core.entity.user.model.ApiUser;

public class ApiAuthenticationSource {
    // Список идентификаторов приложений, посредством которых разрешено управлять услугами
    private final Set<String> servicesApplicationIds;

    // Список идентификаторов приложений, посредством которых разрешено управлять отображаемыми текстами гринурлов
    private final Set<String> displayUrlTextsApplicationIds;

    // Список идентификтаоров приложений, посредством которых разрешено управлять полями лидформ
    private final Set<String> leadformAttributesApplicationIds;

    private final Map<String, RequestSource> requestSourceByAppId;

    public ApiAuthenticationSource(
            Collection<String> servicesApplicationIds,
            Collection<String> displayUrlTextsApplicationIds,
            Collection<String> leadformAttributesApplicationIds,
            Map<String, RequestSource> requestSourceByAppId) {
        this.servicesApplicationIds = new HashSet<>(servicesApplicationIds);
        this.displayUrlTextsApplicationIds = new HashSet<>(displayUrlTextsApplicationIds);
        this.leadformAttributesApplicationIds = new HashSet<>(leadformAttributesApplicationIds);
        this.requestSourceByAppId = new HashMap<>(requestSourceByAppId);
    }

    public ApiUser getChiefOperator() {
        return getAuthentication().getChiefOperator();
    }

    public ApiUser getOperator() {
        return getAuthentication().getOperator();
    }

    public ApiUser getChiefSubclient() {
        return getAuthentication().getChiefSubclient();
    }

    public ApiUser getSubclient() {
        return getAuthentication().getSubjectUser();
    }

    public String getApplicationId() {
        return getAuthentication().getApplicationId();
    }

    /**
     * Получен ли запрос от приложения, которому разрешено управлять услугами.
     */
    public boolean isServicesApplication() {
        return servicesApplicationIds.contains(getAuthentication().getApplicationId());
    }

    /**
     * Получен ли запрос от приложения, которому разрешено управлять отображаемыми текстами гринурлов.
     */
    public boolean isDisplayUrlTextAllowed() {
        return displayUrlTextsApplicationIds.contains(getAuthentication().getApplicationId());
    }

    /**
     * Получен ли запрос от приложения, которому разрешено управлять атрибутами лидформ.
     */
    public boolean isLeadformAttributesAllowed() {
        return leadformAttributesApplicationIds.contains(getAuthentication().getApplicationId());
    }

    /**
     * Возвращает источник запроса, для которого в Api5CampaignAccessibilityChecker должен быть мапинг на
     * соовутствующий инстанс Api5CampaignAccessibilityChecker
     */
    public RequestSource getRequestSource() {
        return requestSourceByAppId.getOrDefault(getAuthentication().getApplicationId(), RequestSource.API_DEFAULT);
    }

    public DirectApiAuthentication getAuthentication() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Class<DirectApiAuthentication> expectedAuthClass = DirectApiAuthentication.class;
        if (authentication == null || !expectedAuthClass.isAssignableFrom(authentication.getClass())) {
            throw new AccessDeniedException("authentication is null or not an instance of " +
                    expectedAuthClass.getName());
        }
        return (DirectApiAuthentication) authentication;
    }
}
