package ru.yandex.canvas.configs.auth;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.yandex.canvas.exceptions.AuthException;
import ru.yandex.canvas.exceptions.UnauthorizedException;
import ru.yandex.direct.env.EnvironmentType;
import ru.yandex.direct.tvm.AllowServices;
import ru.yandex.direct.tvm.TvmIntegration;
import ru.yandex.direct.tvm.TvmService;
import ru.yandex.direct.tvm.UnknownTvmServiceException;
import ru.yandex.inside.passport.tvm2.TvmHeaders;
import ru.yandex.inside.passport.tvm2.exceptions.IncorrectTvmServiceTicketException;
import ru.yandex.inside.passport.tvm2.exceptions.IncorrectTvmUserTicketException;
import ru.yandex.inside.passport.tvm2.exceptions.MissingTvmServiceTicketException;
import ru.yandex.inside.passport.tvm2.exceptions.MissingTvmUserTicketException;

import static java.util.Arrays.asList;

public class TvmAuthorizer implements CanvasAuthorizer {
    private static final Logger logger = LoggerFactory.getLogger(CanvasAuthorizer.class);

    private final TvmIntegration tvmIntegration;
    private final EnvironmentType envType;
    private final CanvasAuthorizer supplementaryAuthorizer;

    public TvmAuthorizer(TvmIntegration tvmIntegration, EnvironmentType envType,
            CanvasAuthorizer supplementaryAuthorizer) {
        this.tvmIntegration = tvmIntegration;
        this.envType = envType;
        this.supplementaryAuthorizer = supplementaryAuthorizer;
    }

    @Override
    public void authorize(HttpServletRequest request, AuthorizeBy authorizeByAnnotation) throws AuthException, UnauthorizedException {
        String serviceTicket = request.getHeader(TvmHeaders.SERVICE_TICKET);

        AllowServices allowedServices = authorizeByAnnotation.tvmAllowedServices();

        if (serviceTicket == null) {
            logger.debug("Absent service ticket in header {}", TvmHeaders.SERVICE_TICKET);
            throw new UnauthorizedException("");
        }

        TvmService sourceService;
        try {
            sourceService = tvmIntegration.getTvmService(serviceTicket);
        } catch (IncorrectTvmServiceTicketException
                | IncorrectTvmUserTicketException
                | MissingTvmServiceTicketException
                | MissingTvmUserTicketException
                | UnknownTvmServiceException exception) {
            throw new UnauthorizedException(exception.getMessage());
        }

        TvmService[] allowed;
        if (envType.isProductionOrPrestable()) {
            allowed = allowedServices.production();
        } else if (envType.isProductionSandbox()) {
            allowed = allowedServices.sandbox();
        } else if (envType.isSandbox()) {
            allowed = allowedServices.sandboxTesting();
        } else {
            allowed = allowedServices.testing();
        }

        if (!ArrayUtils.contains(allowed, sourceService)) {
            logger.warn("TVM check failed. ClientId {} is not in AllowServices {}", sourceService, asList(allowed));
            throw new AuthException();
        }

        supplementaryAuthorizer.authorize(request, authorizeByAnnotation);
    }
}
