package ru.yandex.webmaster3.internal.common.filter;

import java.nio.charset.StandardCharsets;
import java.util.Optional;

import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.server.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import ru.yandex.webmaster3.core.http.Action;
import ru.yandex.webmaster3.core.http.RequestFilter;
import ru.yandex.webmaster3.core.http.request.RequestContext;
import ru.yandex.webmaster3.core.security.tvm.TVM2AuthService;
import ru.yandex.webmaster3.core.security.tvm.TVMServiceTicket;
import ru.yandex.webmaster3.core.security.tvm.TVMTokenService;
import ru.yandex.webmaster3.internal.common.InternalAction;
import ru.yandex.webmaster3.internal.common.InternalRequest;
import ru.yandex.webmaster3.internal.common.security.InternalACLService;
import ru.yandex.webmaster3.internal.common.security.InternalClient;
import ru.yandex.webmaster3.internal.common.security.InternalGrant;
import ru.yandex.webmaster3.internal.common.security.InternalGrantOptions;

/**
 * Тикет для тестинга, который никогда не протухает (TVM 1.0):
 * 2:B7:1971952644:7F:CD0:M36hGz5iJ5NEqQtkkdzTJ0j8wOO00Wu5HKdP6lyILQ9wZamv2ylyrKsrjpIpVK0qKdnfA52W4ZLVLTs-kuScCf8mRjH8f3OquDxFyVu-UbHBfvuudb3Jcupm-Dvu4exwnR4PGCCJw7fvJLID2py9q1BLcgGUAiivAlCLjUdJxOg
 * @author avhaliullin
 */
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class InternalAPISecurityFilter implements RequestFilter<InternalRequest, InternalAPISecurityFilterResponse> {
    private static final Logger log = LoggerFactory.getLogger(InternalAPISecurityFilter.class);

    private final TVM2AuthService tvm2AuthService;
    private final InternalACLService internalACLService;

    @Override
    public InternalAPISecurityFilterResponse beforeRequest(RequestContext ctx, InternalRequest internalRequest) {
        Action action = ctx.getAction();
        if (!(action instanceof InternalAction)) {
            throw new RuntimeException("Cannot get grants for action " + action.getClass() + ". Action should extend InternalAction");
        }
        InternalAction internalAction = (InternalAction) action;

        InternalGrant requiredGrant = internalAction.getGrant();
        Request httpRequest = ctx.getHttpRequest();
        String tvm2ticketString = httpRequest.getHeader(TVMTokenService.TVM2_TICKET_HEADER);
        if (StringUtils.isEmpty(tvm2ticketString)) {
            return new InternalAPISecurityFilterResponse.InvalidTiket("Missing TVM ticket in '" + TVMTokenService.TVM2_TICKET_HEADER + "' header");
        }
        TVMServiceTicket ticket = tvm2AuthService.validateTicket(tvm2ticketString.getBytes(StandardCharsets.US_ASCII));
        if (ticket == null) {
            return new InternalAPISecurityFilterResponse.InvalidTiket("TVM 2.0 Ticket validation failed");
        }
        log.info("Authenticated client {}", ticket.getClientId());
        Optional<InternalClient> clientOpt = internalACLService.getClientInfo(ticket.getClientId());
        if (clientOpt.isEmpty() || !clientOpt.get().getGrants().containsKey(requiredGrant)) {
            return new InternalAPISecurityFilterResponse.NotAuthorized("Not authorized to perform requested action");
        }
        InternalGrantOptions grantOptions = clientOpt.get().getGrants().get(requiredGrant);
        InternalClient client = clientOpt.get();
        log.info("Authorized client {} ({}) for action by grant {} with options {}", client.getClientId(), client.getName(), requiredGrant, grantOptions);
        internalRequest.setInternalClient(client);
        internalRequest.setGrantOptions(grantOptions);
        return null;
    }
}
