<?php

declare(strict_types=1);

namespace Rowbot\URL\State;

use Rowbot\URL\Component\PathSegment;
use Rowbot\URL\ParserContext;
use Rowbot\URL\ParserState;
use Rowbot\URL\String\CodePoint;

/**
 * @see https://url.spec.whatwg.org/#path-start-state
 */
class PathStartState implements State
{
    public function handle(ParserContext $context, string $codePoint): StatusCode
    {
        // 1. If url is special, then:
        if ($context->url->scheme->isSpecial()) {
            // 1.1. If c is U+005C (\), validation error.
            if ($codePoint === '\\') {
                // Validation error.
                $context->logger?->notice('invalid-reverse-solidus', [
                    'input'  => (string) $context->input,
                    'column' => $context->iter->key() + 1,
                ]);
            }

            // 1.2. Set state to path state.
            $context->state = ParserState::PATH;

            // 1.3. If c is neither U+002F (/) nor U+005C (\), then decrease pointer by 1.
            if ($codePoint !== '/' && $codePoint !== '\\') {
                $context->iter->prev();
            }

            return StatusCode::OK;
        }

        // 2. Otherwise, if state override is not given and c is U+003F (?), set url’s query to the empty string and
        // state to query state.
        if (!$context->isStateOverridden() && $codePoint === '?') {
            $context->url->query = '';
            $context->state = ParserState::QUERY;

            return StatusCode::OK;
        }

        // 3. Otherwise, if state override is not given and c is U+0023 (#), set url’s fragment to the empty string and
        // state to fragment state.
        if (!$context->isStateOverridden() && $codePoint === '#') {
            $context->url->fragment = '';
            $context->state = ParserState::FRAGMENT;

            return StatusCode::OK;
        }

        // 4. Otherwise, if c is not the EOF code point:
        if ($codePoint !== CodePoint::EOF) {
            // 4.1. Set state to path state.
            $context->state = ParserState::PATH;

            // 4.2. If c is not U+002F (/), then decrease pointer by 1.
            if ($codePoint !== '/') {
                $context->iter->prev();
            }

            return StatusCode::OK;
        }

        // 5. Otherwise, if state override is given and url’s host is null, append the empty string to url’s path.
        if ($context->isStateOverridden() && $context->url->host->isNull()) {
            $context->url->path->push(new PathSegment());
        }

        return StatusCode::OK;
    }
}
