package ru.yandex.wmconsole.authorization;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.common.framework.core.ServRequest;
import ru.yandex.wmconsole.error.ClientException;
import ru.yandex.wmconsole.error.ClientProblem;
import ru.yandex.wmtools.common.data.info.OAuthInfo;
import ru.yandex.wmtools.common.error.BlackboxException;
import ru.yandex.wmtools.common.error.BlackboxProblem;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.OAuthException;
import ru.yandex.wmtools.common.error.UserException;
import ru.yandex.wmtools.common.service.IViewerUserIdService;
import ru.yandex.wmtools.common.service.OAuthService;

/**
 * @author aherman
 */
public class ApiOAuthInfoService {
    private static final Logger log = LoggerFactory.getLogger(ApiOAuthInfoService.class);

    private static final String AUTHORIZATION_HEADER_CONTENT_PREFIX = "OAuth ";
    private static final String AUTHORIZATION_HEADER_NAME = "authorization:";

    private OAuthService oAuthService;
    private IViewerUserIdService viewerUserIdService;

    public OAuthInfo getOAuthInfo(ServRequest req) throws ClientException, InternalException {
        String authToken = null;
        //todo (minor) check header delimiter
        for (String header : req.getHttpHeaders().split("\n")) {
            //todo (minor) check header format (ws)
            if (header.toLowerCase().startsWith(AUTHORIZATION_HEADER_NAME)) {
                authToken = header.substring(AUTHORIZATION_HEADER_NAME.length());
            }
        }

        if (authToken == null) {
            log.debug("no authorization header found");
            throw new ClientException(ClientProblem.BAD_FORMAT, "No authorization header");
        }

        authToken = authToken.trim();
        if (authToken.startsWith(AUTHORIZATION_HEADER_CONTENT_PREFIX)) {
            authToken = authToken.substring(AUTHORIZATION_HEADER_CONTENT_PREFIX.length()).trim();
        } else {
            throw new ClientException(ClientProblem.BAD_FORMAT, "Wrong format of authorization header");
        }

        OAuthInfo oAuthInfo;
        try {
            oAuthInfo = oAuthService.getOAuthInfo(authToken);
        } catch (BlackboxException e) {
            if (BlackboxProblem.INVALID_PARAMS.equals(e.getBlackboxProblem())) {
                throw new ClientException(ClientProblem.BAD_FORMAT, "Wrong format of authorization header");
            } else {
                throw new ClientException(ClientProblem.INTERNAL_ERROR, "Unable to check authorization", e);
            }
        } catch (OAuthException e) {
            if ("INVALID".equals(e.getoAuthProblem())) {
                throw new ClientException(ClientProblem.EXPIRED_TOKEN, "Expired token");
            } else {
                throw new ClientException(ClientProblem.INTERNAL_ERROR, "Unable to check authorization", e);
            }
        }

        try {
            viewerUserIdService.assureUserIsInUsersList(oAuthInfo.getUid());
            viewerUserIdService.checkUserIsNotBlockedAndAcceptedLicence(oAuthInfo.getUid());
        } catch (UserException e) {
            throw new ClientException(ClientProblem.WRONG_USER_ID, e.getMessage(), e);
        }

        return oAuthInfo;
    }

    @Required
    public void setoAuthService(OAuthService oAuthService) {
        this.oAuthService = oAuthService;
    }

    @Required
    public void setViewerUserIdService(IViewerUserIdService viewerUserIdService) {
        this.viewerUserIdService = viewerUserIdService;
    }
}
