package com.atlassian.bitbucket.installer.scripts;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.TreeMap;

import static java.nio.file.StandardOpenOption.READ;

class BitbucketConfigMatcher extends TypeSafeDiagnosingMatcher<Path> {

    private static final String KEY_CFG_MODE = "application.mode";
    private final Map<String, String> properties = new TreeMap<>();

    private static Map<String, String> readProperties(Path item) {
        Properties properties = new Properties();
        if (Files.exists(item)) {
            try (InputStream stream = Files.newInputStream(item, READ)) {
                properties.load(stream);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        Map<String, String> result = new TreeMap<>();
        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            result.put(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
        }

        return result;
    }

    BitbucketConfigMatcher inMirrorMode() {
        return withProperty(KEY_CFG_MODE, "mirror");
    }

    BitbucketConfigMatcher inDefaultMode() {
        return withoutProperty(KEY_CFG_MODE);
    }

    BitbucketConfigMatcher withProperty(String key, String value) {
        properties.put(key, value);
        return this;
    }

    BitbucketConfigMatcher withoutProperty(String key) {
        properties.remove(key);
        return this;
    }

    @Override
    protected boolean matchesSafely(Path item, Description mismatchDescription) {
        Map<String, String> actualProperties = readProperties(item);

        if (Objects.equals(actualProperties, properties)) {
            return true;
        } else {
            mismatchDescription.appendValue(actualProperties);
            return false;
        }
    }

    @Override
    public void describeTo(Description description) {
        description.appendValue(properties);
    }
}
