package com.atlassian.stash.internal.check;

import com.atlassian.bitbucket.Product;
import com.atlassian.bitbucket.auth.AuthenticationContext;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.i18n.KeyedMessage;
import com.atlassian.bitbucket.license.LicenseService;
import com.atlassian.bitbucket.nav.NavBuilder;
import com.atlassian.bitbucket.scm.ScmRequest;
import com.atlassian.bitbucket.scm.ScmRequestCheck;
import com.atlassian.bitbucket.server.ApplicationMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Nonnull;
import java.io.IOException;

@Component
public class LicensingCheck implements ScmRequestCheck {

    private final AuthenticationContext authenticationContext;
    private final I18nService i18nService;
    private final LicenseService licenseService;
    private final ApplicationMode mode;
    private final NavBuilder navBuilder;

    @Autowired
    public LicensingCheck(LicenseService licenseService, I18nService i18nService, NavBuilder navBuilder,
                          AuthenticationContext authenticationContext,
                          @Value("#{applicationPropertiesService.mode}") ApplicationMode mode) {
        this.authenticationContext = authenticationContext;
        this.i18nService = i18nService;
        this.licenseService = licenseService;
        this.mode = mode;
        this.navBuilder = navBuilder;
    }

    @Override
    public boolean check(@Nonnull ScmRequest request) throws IOException {
        // we skip licensing checks for all SCM operations on mirrors. License checking for read-only SCM operations
        // is handled by the upstream through delegated auth. For write operations SCM operations we need to provide
        // a mirror-specific message (we don't allow write operations at present) so we let this fall through to
        // ReadOnlyRequestCheck
        if (mode == ApplicationMode.MIRROR) {
            return true;
        }

        if (request.isWrite()) {
            //This will catch the cases of the license being exceeded, but in the grace period
            if (licenseService.isLicenseValid()) {
                return true;
            }

            KeyedMessage message = licenseService.getStatus();

            if (message != null) {
                request.sendError(
                        i18nService.getMessage("bitbucket.scm.license.limit.exceeded"),
                        i18nService.getMessage("bitbucket.scm.license.limit.exceeded.detail",
                                Product.NAME, navBuilder.buildAbsolute(), message.getLocalisedMessage())
                );
                return false;
            }
        }

        if (authenticationContext.isAuthenticated() && !licenseService.canLogin(authenticationContext.getCurrentUser())) {
            request.sendError(
                    i18nService.getMessage("bitbucket.scm.unlicensed.user"),
                    i18nService.getMessage("bitbucket.scm.unlicensed.user.detail",
                            Product.NAME)
            );
            return false;
        }

        return true;
    }
}
