package it.com.atlassian.bitbucket.distribution;

import com.atlassian.pageobjects.Defaults;
import com.atlassian.pageobjects.ProductInstance;
import com.atlassian.pageobjects.TestedProductFactory;
import com.atlassian.bitbucket.test.RepositoryTestHelper;
import com.atlassian.bitbucket.test.BitbucketTestLicense;
import com.atlassian.webdriver.bitbucket.BitbucketTestedProduct;
import com.atlassian.webdriver.bitbucket.page.*;
import com.atlassian.webdriver.bitbucket.page.setup.SetupAdminUserPage;
import com.atlassian.webdriver.bitbucket.page.setup.SetupDatabasePage;
import com.atlassian.webdriver.bitbucket.page.setup.SetupSettingsPage;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.response.Response;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ClassPathResource;

import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

public class FirstRunTest {

    private static final BitbucketTestLicense STANDALONE_LICENSE = BitbucketTestLicense.builder()
            .whenNonClustered(
                    "AAABHg0ODAoPeNptkEFrwkAQhe/+ioWeI0mMhwoL1RipYEwwtgVv0+2kWYi7YWYj9d9X43qw9Pref" +
                    "O/NzNMHfokcSESJiKazcDKbPous2os4jOIRO+BmnJ2g7cFpa2QNLaOXl8iKdDfoe2QnWq3QMIrak" +
                    "nANigpd34lVb5S4+ixsLaor6gNSwiF1CQ7ltS8IJ0GU3F1rHCi3hSPKUiPRvTcHbRwaMAqzn07Te" +
                    "eDL6NX7F0ifUDrq8TEqu5Ct7LCzmqx7AdcCswYzVvboJze3E/bnDofitMjzbJeu55tRhXRCWi/lI" +
                    "jmsgrDK1kG6WxyC92I79XQJ5AzSQHqpoG8wmm/fm98bvbntj59IRf3GSCzjxx3+va3sSTXA+Pdlv" +
                    "zUInXUwLQIVAJPALS44YIOLoi1gP9UzA6y0IU1rAhQCZCUupoxQuFvWoD1nt9f2QUGQ+g==X02ei")
            .build();

    public static final String LOCALHOST = "localhost";

    //Note: The ProductInstance bit is a bit of a hack to get around the fact that the distribution has no context path,
    //      so the StashTestedProduct that is created otherwise ends up being wrong (it has a /stash context path) and
    //      so the test fails.
    private static final ProductInstance PRODUCT = new ProductInstance() {

        private final Defaults annotation = AnnotationUtils.getAnnotation(BitbucketTestedProduct.class, Defaults.class);

        @Override
        public String getBaseUrl() {
            return String.format("http://%s:%d", LOCALHOST, getHttpPort());
        }

        @Override
        public int getHttpPort() {
            return annotation.httpPort();
        }

        @Override
        public String getContextPath() {
            return "/";
        }

        @Override
        public String getInstanceId() {
            return annotation.instanceId();
        }
    };

    private static final BitbucketTestedProduct BITBUCKET = TestedProductFactory.create(BitbucketTestedProduct.class, PRODUCT, null);
    private static final String USERNAME = "admin";
    private static final String PASSWORD = "testPassword1";
    private static final String PROJ_KEY = "PROJ";
    private static final String REPO_SLUG = "repo";

    @Rule
    public TemporaryFolder tmpFolder = new TemporaryFolder();

    @Before
    public void setup() throws InterruptedException {
        long timeout = System.nanoTime() + TimeUnit.MINUTES.toNanos(5);

        Logger log = LoggerFactory.getLogger(getClass());
        do {
            Response response = RestAssured.get(PRODUCT.getBaseUrl() + "/status");
            if (response.getStatusCode() == 200) {
                log.info("Bitbucket has started");

                return;
            }
            if (response.getStatusCode() == 503) {
                log.info("Waiting for Bitbucket to start ({})", response.jsonPath().getString("state"));
            }

            Thread.sleep(TimeUnit.SECONDS.toMillis(5));
        } while (System.nanoTime() < timeout);

        fail("Timed out waiting for Bitbucket to start");
    }

    @Test
    public void testFirstRun() throws Exception {
        // Select internal database
        SetupDatabasePage databasePage = BITBUCKET.visit(SetupDatabasePage.class);
        
        //Enter a license
        SetupSettingsPage settingsPage = databasePage.clickNext();
        settingsPage.enterApplicationTitle("Bitbucket First Run");
        settingsPage.enterBaseURL(PRODUCT.getBaseUrl());
        settingsPage.clickHasKey();
        settingsPage.enterLicense(STANDALONE_LICENSE.get());
        //Create the first user
        SetupAdminUserPage userPage = settingsPage.clickNext();
        userPage.setUsername(USERNAME);
        userPage.setFullname("System Administrator");
        userPage.setEmail("admin@example.com");
        userPage.setPassword(PASSWORD);
        userPage.setConfirmPassword(PASSWORD);

        //Login with that user
        BitbucketLoginPage loginPage = userPage.clickSkipJiraSuccess();

        GettingStartedPage gettingStartedPage = loginPage.login(USERNAME, PASSWORD, GettingStartedPage.class);
        assertTrue(gettingStartedPage.isHere());

        //End up on the project list, and then logout
        ProjectListPage listPage = gettingStartedPage.nextPage(ProjectListPage.class);

        ProjectCreatePage createProjPage = listPage.goToCreateProjectPage();
        createProjPage.setKey(PROJ_KEY);
        createProjPage.setName("Project");
        RepositoryCreatePage createRepoPage = createProjPage.submitSuccess().clickCreateRepository();
        createRepoPage.setName(REPO_SLUG);
        createRepoPage.submitSuccess().logout();

        ClassPathResource repositoryResource = new ClassPathResource("git/default-repository.zip");
        RepositoryTestHelper.pushRep(tmpFolder, String.format("http://%s:%s@%s:%d", USERNAME, PASSWORD,
                LOCALHOST, PRODUCT.getHttpPort()), USERNAME, PASSWORD, PROJ_KEY, REPO_SLUG, repositoryResource);
    }
}