<?php
namespace Misuzu\URLs;

use InvalidArgumentException;

class URLRegistry {
    private array $infos = [];

    public function register(string $name, string $path, array $query = [], string $fragment = ''): void {
        if(array_key_exists($name, $this->infos))
            throw new InvalidArgumentException('A URL with $name has already been registered.');

        $this->infos[$name] = new URLInfo($name, $path, $query, $fragment);
    }

    public function registerInfo(URLInfo $info): void {
        if(array_key_exists($info->getName(), $this->infos))
            throw new InvalidArgumentException('A URL with $name has already been registered.');

        $this->infos[$info->getName()] = $info;
    }

    public function format(string $name, array $vars = [], bool $spacesAsPlus = false): string {
        if(!array_key_exists($name, $this->infos))
            return '';

        $urlInfo = $this->infos[$name];
        $urlStr = self::replaceVariables($urlInfo->getPath(), $vars);

        if($urlInfo->hasQuery()) {
            $query = [];
            $queryParts = $urlInfo->getQuery();
            foreach($queryParts as $name => $value) {
                $value = self::replaceVariables($value, $vars);
                if($value !== '' && !($name === 'page' && (int)$value <= 1))
                    $query[$name] = $value;
            }

            if(!empty($query))
                $urlStr .= '?' . http_build_query($query, '', '&', $spacesAsPlus ? PHP_QUERY_RFC1738 : PHP_QUERY_RFC3986);
        }

        if($urlInfo->hasFragment()) {
            $fragment = self::replaceVariables($urlInfo->getFragment(), $vars);
            if($fragment !== '')
                $urlStr .= '#' . $fragment;
        }

        return $urlStr;
    }

    public static function replaceVariables(string $str, array $vars): string {
        // i: have no idea what i'm doing
        $out = '';
        $varName = '';
        $inVarName = false;

        $length = strlen($str);
        for($i = 0; $i < $length; ++$i) {
            $char = $str[$i];

            if($inVarName) {
                if($char === '>') {
                    $inVarName = false;
                    if(array_key_exists($varName, $vars)) {
                        $varValue = $vars[$varName];
                        if(is_array($varValue))
                            $varValue = empty($varValue) ? '' : implode(',', $varValue);
                        elseif(is_int($varValue))
                            $varValue = ($varName === 'page' ? $varValue < 2 : $varValue === 0) ? '' : (string)$varValue;
                        else
                            $varValue = (string)$varValue;
                    } else
                        $varValue = '';

                    $out .= $varValue;
                    $varName = '';
                    continue;
                }

                if($char === '<') {
                    $out .= '<' . $varName;
                    $varName = '';
                    continue;
                }

                $varName .= $char;
            } else
                $inVarName = $char === '<';

            if(!$inVarName)
                $out .= $char;
        }

        if($varName !== '')
            $out .= $varName;

        return $out;
    }
}
