<?php

namespace Lucent\Schema\Validator;

use Lucent\Channel\ChannelService;
use Lucent\Edge\EdgeCollection;
use Lucent\Primitive\Collection;
use Lucent\Record\RecordData;
use Lucent\Schema\FieldInterface;


class Validator
{


    function __construct(
        public ChannelService $channelService
    )
    {
    }

    /**
     * @return  Collection<ValidatorError>
     */
    public function check(
        string          $schemaName,
        RecordData      $data,
        ?EdgeCollection $edges,
    ): Collection
    {

        $schema = $this->channelService->getSchema($schemaName)->get();
        return $schema->fields
            ->map(fn(FieldInterface $f) => $this->validate($f, $data, $edges))
            ->filter(fn(?ValidatorError $error) => !empty($error))
            ->values();
    }


    public function validate(FieldInterface $field, RecordData $recordData, ?EdgeCollection $edges): ?ValidatorError
    {
        $value = $recordData->get($field->name);
        if ($field instanceof RequiredInterface && $field->required && $field->failRequired($value)) {
            return new ValidatorError($field->name, $field->label, "Field is required");
        }

        if ($field instanceof MinMaxInterface && !is_null($field->min) && $field->failMin($value)) {
            return new ValidatorError($field->name, $field->label, "The minimum {$field->label} can be {$field->min}");
        }

        if ($field instanceof MinMaxInterface && !is_null($field->max) && $field->failMax($value)) {
            return new ValidatorError($field->name, $field->label, "The maximum {$field->label} can be {$field->min}");
        }

        return null;
    }

    /**
     * @param Collection<ValidatorError> $errors
     * @throws ValidatorException
     */
    public function throwException(Collection $errors): void
    {
        throw new ValidatorException($this->errorsByField($errors));
    }

    /**
     * @param Collection<ValidatorError> $errors
     * @return array<string,ValidatorError>
     **/
    public function errorsByField(Collection $errors): array
    {

        return collect($errors)->keyBy("fieldName")->toArray();
    }


}
