<?php

declare(strict_types=1);

/**
 * This code was auto-generated by {this script}[https://github.com/cucumber/messages/blob/main/jsonschema/scripts/codegen.rb]
 */

namespace Cucumber\Messages;

use JsonSerializable;
use Cucumber\Messages\DecodingException\SchemaViolationException;

/**
 * Represents the Source message in Cucumber's message protocol
 * @see https://github.com/cucumber/messages
 *
 * //// Source
 *
 * A source file, typically a Gherkin document or Java/Ruby/JavaScript source code */
final class Source implements JsonSerializable
{
    use JsonEncodingTrait;

    /**
     * Construct the Source with all properties
     *
     */
    public function __construct(

        /**
         * The [URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)
         * of the source, typically a file path relative to the root directory
         */
        public readonly string $uri = '',

        /**
         * The contents of the file
         */
        public readonly string $data = '',

        /**
         * The media type of the file. Can be used to specify custom types, such as
         * text/x.cucumber.gherkin+plain
         */
        public readonly Source\MediaType $mediaType = Source\MediaType::TEXT_X_CUCUMBER_GHERKIN_PLAIN,
    ) {
    }

    /**
     * @throws SchemaViolationException
     *
     * @internal
     */
    public static function fromArray(array $arr): self
    {
        self::ensureUri($arr);
        self::ensureData($arr);
        self::ensureMediaType($arr);

        return new self(
            (string) $arr['uri'],
            (string) $arr['data'],
            Source\MediaType::from((string) $arr['mediaType']),
        );
    }

    /**
     * @psalm-assert array{uri: string|int|bool} $arr
     */
    private static function ensureUri(array $arr): void
    {
        if (!array_key_exists('uri', $arr)) {
            throw new SchemaViolationException('Property \'uri\' is required but was not found');
        }
        if (array_key_exists('uri', $arr) && is_array($arr['uri'])) {
            throw new SchemaViolationException('Property \'uri\' was array');
        }
    }

    /**
     * @psalm-assert array{data: string|int|bool} $arr
     */
    private static function ensureData(array $arr): void
    {
        if (!array_key_exists('data', $arr)) {
            throw new SchemaViolationException('Property \'data\' is required but was not found');
        }
        if (array_key_exists('data', $arr) && is_array($arr['data'])) {
            throw new SchemaViolationException('Property \'data\' was array');
        }
    }

    /**
     * @psalm-assert array{mediaType: string|int|bool} $arr
     */
    private static function ensureMediaType(array $arr): void
    {
        if (!array_key_exists('mediaType', $arr)) {
            throw new SchemaViolationException('Property \'mediaType\' is required but was not found');
        }
        if (array_key_exists('mediaType', $arr) && is_array($arr['mediaType'])) {
            throw new SchemaViolationException('Property \'mediaType\' was array');
        }
    }
}
