#include "url_parts.h"

namespace NModRedirects::NImpl {

    TUrl SplitUrl(TStringBuf url) noexcept {
        TUrl res;

        if (url.StartsWith("//")) {
            res.Scheme = "//";
            url.Skip(2);
        }

        auto schemePos = res.Scheme ? TStringBuf::npos : url.find("://");
        auto schemeEnd = 0;
        auto pathPos = url.find('/');
        auto queryPos = url.find('?');
        auto fragPos = url.find('#');

        if (schemePos > std::min({pathPos, queryPos, fragPos})) {
            schemePos = TStringBuf::npos;
        }

        if (schemePos != TStringBuf::npos) {
            schemeEnd = schemePos + 3;
            pathPos = url.find('/', schemeEnd);
            res.Scheme = url.SubStr(0, schemeEnd);
        }

        if (pathPos > std::min({queryPos, fragPos})) {
            pathPos = TStringBuf::npos;
        }

        if (queryPos > fragPos) {
            queryPos = TStringBuf::npos;
        }

        if (fragPos != TStringBuf::npos) {
            res.Fragment = url.SubStr(fragPos + 1);
            url = url.SubStr(0, fragPos);
        }

        if (queryPos != TStringBuf::npos) {
            res.Query = url.SubStr(queryPos + 1);
            url = url.SubStr(0, queryPos);
        }

        if (res.Scheme) {
            if (pathPos != TStringBuf::npos) {
                res.Path = url.SubStr(pathPos);
                res.Host = url.SubStr(schemeEnd, pathPos - schemeEnd);
            } else {
                res.Host = url.SubStr(schemeEnd);
            }
        } else {
            res.Path = url;
        }

        return res;
    }

    TString MergeUrl(TUrl src) noexcept {
        TString res(Reserve(
            src.Scheme.size() + src.Host.size() + src.Path.size()
            + src.Query.size()
            + src.Fragment.size()
            + 2
        ));
        res.append(src.Scheme).append(src.Host).append(src.Path);
        if (src.Query) {
            res.append('?').append(src.Query);
        }
        if (src.Fragment) {
            res.append('#').append(src.Fragment);
        }
        return res;
    }

    TUrl ReplaceUrlParts(TUrl from, TUrl with, TUrlParts what) noexcept {
        return {
            .Scheme = from.Scheme,
            .Host   = (what.host    ? with.Host     : from.Host),
            .Path   = (what.path    ? with.Path     : from.Path),
            .Query  = (what.query   ? with.Query    : from.Query),
            .Fragment = (what.fragment ? with.Fragment : from.Fragment),
        };
    }
}

template <>
void Out<NModRedirects::NImpl::TUrl>(IOutputStream& out, const NModRedirects::NImpl::TUrl& url) {
    out << "{scheme=" << TString(url.Scheme).Quote()
        << ";host=" << TString(url.Host).Quote()
        << ";path=" << TString(url.Path).Quote()
        << ";query=" << TString(url.Query).Quote()
        << ";fragment=" << TString(url.Fragment).Quote()
        << "}";
}
