<?php

declare(strict_types=1);

namespace App\Helpers;

use Respect\Validation\Validator as v;

class Validator
{
    private array $errors = [];
    private array $data;

    public function __construct(array $data)
    {
        $this->data = $data;
    }

    public function required(string $field, string $label = ''): self
    {
        $label = $label ?: $field;
        $value = $this->data[$field] ?? null;

        if ($value === null || $value === '') {
            $this->errors[$field][] = "{$label} es obligatorio";
        }

        return $this;
    }

    public function email(string $field, string $label = ''): self
    {
        $label = $label ?: $field;
        $value = $this->data[$field] ?? null;

        if ($value !== null && $value !== '' && !v::email()->validate($value)) {
            $this->errors[$field][] = "{$label} no es un correo válido";
        }

        return $this;
    }

    public function minLength(string $field, int $min, string $label = ''): self
    {
        $label = $label ?: $field;
        $value = $this->data[$field] ?? null;

        if ($value !== null && strlen($value) < $min) {
            $this->errors[$field][] = "{$label} debe tener al menos {$min} caracteres";
        }

        return $this;
    }

    public function maxLength(string $field, int $max, string $label = ''): self
    {
        $label = $label ?: $field;
        $value = $this->data[$field] ?? null;

        if ($value !== null && strlen($value) > $max) {
            $this->errors[$field][] = "{$label} no debe exceder {$max} caracteres";
        }

        return $this;
    }

    public function inValues(string $field, array $values, string $label = ''): self
    {
        $label = $label ?: $field;
        $value = $this->data[$field] ?? null;

        if ($value !== null && $value !== '' && !in_array($value, $values)) {
            $this->errors[$field][] = "{$label} no es un valor válido";
        }

        return $this;
    }

    public function numeric(string $field, string $label = ''): self
    {
        $label = $label ?: $field;
        $value = $this->data[$field] ?? null;

        if ($value !== null && $value !== '' && !is_numeric($value)) {
            $this->errors[$field][] = "{$label} debe ser numérico";
        }

        return $this;
    }

    public function date(string $field, string $label = ''): self
    {
        $label = $label ?: $field;
        $value = $this->data[$field] ?? null;

        if ($value !== null && $value !== '' && !strtotime($value)) {
            $this->errors[$field][] = "{$label} no es una fecha válida";
        }

        return $this;
    }

    public function matches(string $field, string $matchField, string $label = ''): self
    {
        $label = $label ?: $field;
        $value = $this->data[$field] ?? null;
        $matchValue = $this->data[$matchField] ?? null;

        if ($value !== $matchValue) {
            $this->errors[$field][] = "{$label} no coincide";
        }

        return $this;
    }

    public function passes(): bool
    {
        return empty($this->errors);
    }

    public function fails(): bool
    {
        return !empty($this->errors);
    }

    public function errors(): array
    {
        return $this->errors;
    }

    public function firstError(): ?string
    {
        foreach ($this->errors as $messages) {
            return $messages[0];
        }
        return null;
    }
}
