package org.whoneedhelp.mobile;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;

final class TrustedOrigin {
    private final URI base;
    private final int port;

    private TrustedOrigin(URI base) {
        this.base = base;
        this.port = effectivePort(base);
    }

    static TrustedOrigin parse(String value, boolean debugBuild) {
        final URI uri;

        try {
            uri = new URI(value);
        } catch (URISyntaxException exception) {
            throw new IllegalArgumentException("BASE_URL is not a valid URI", exception);
        }

        String scheme = normalized(uri.getScheme());
        boolean acceptedScheme = "https".equals(scheme) || (debugBuild && "http".equals(scheme));

        if (
            !acceptedScheme ||
            uri.getHost() == null ||
            uri.getHost().trim().isEmpty() ||
            uri.getUserInfo() != null ||
            !pathIsOrigin(uri.getPath()) ||
            uri.getQuery() != null ||
            uri.getFragment() != null
        ) {
            throw new IllegalArgumentException("BASE_URL must be an absolute trusted origin");
        }

        return new TrustedOrigin(uri.normalize());
    }

    String startUrl() {
        return base.toString();
    }

    String originRule() {
        try {
            return new URI(
                normalized(base.getScheme()),
                null,
                base.getHost(),
                base.getPort(),
                null,
                null,
                null
            ).toString();
        } catch (URISyntaxException exception) {
            throw new IllegalStateException("Trusted origin could not be normalized", exception);
        }
    }

    boolean matches(String value) {
        try {
            URI candidate = new URI(value);

            return normalized(base.getScheme()).equals(normalized(candidate.getScheme()))
                && normalized(base.getHost()).equals(normalized(candidate.getHost()))
                && port == effectivePort(candidate)
                && candidate.getUserInfo() == null;
        } catch (URISyntaxException exception) {
            return false;
        }
    }

    boolean matchesOrigin(String value) {
        try {
            URI candidate = new URI(value);

            return matches(value)
                && pathIsOrigin(candidate.getPath())
                && candidate.getQuery() == null
                && candidate.getFragment() == null;
        } catch (URISyntaxException exception) {
            return false;
        }
    }

    private static boolean pathIsOrigin(String path) {
        return path == null || path.isEmpty() || "/".equals(path);
    }

    private static int effectivePort(URI uri) {
        if (uri.getPort() != -1) {
            return uri.getPort();
        }

        return "https".equals(normalized(uri.getScheme())) ? 443 : 80;
    }

    private static String normalized(String value) {
        return value == null ? "" : value.toLowerCase(Locale.ROOT);
    }
}
