<?php
namespace nur\sery\wip\schema\_scalar;

use Exception;
use nulib\tests\TestCase;
use nulib\ValueException;
use nur\sery\wip\schema\input\Input;

class ScalarValueTest extends TestCase {
  function checkValue(ScalarWrapper $value, $dest, bool $present, bool $available, bool $valid, bool $normalized): void {
    self::assertSame($dest, $value->get(), "value");
    self::assertSame($present, $value->isPresent(), "present");
    self::assertSame($available, $value->isAvailable(), "available");
    self::assertSame($valid, $value->isValid(), "valid");
    self::assertSame($normalized, $value->isNormalized(), "normalized");
  }

  function checkVerifix(ScalarSchema $schema, $src, bool $verifix, $dest, bool $present, bool $available, bool $valid, bool $normalized, ?array $inputParams=null): void {
    $value = $schema->newWrapper();
    if ($inputParams !== null) $input = new Input($src, $inputParams);
    else $input = $src;
    $value->reset($input, null, $verifix);
    $this->checkValue($value, $dest, $present, $available, $valid, $normalized);
  }

  function checkException(ScalarSchema $schema, $src, bool $verifix, string $exceptionClass, ?array $inputParams=null) {
    $value = $schema->newWrapper();
    if ($inputParams !== null) $src = new Input($src, $inputParams);
    self::assertException($exceptionClass, function() use ($value, &$src, $verifix) {
      $value->reset($src, null, $verifix);
    });
  }

  function testRawstring() {
    $schema = new ScalarSchema("rawstring");

    $this->checkVerifix($schema, null, false, null, true, true, false, false);
    $this->checkException($schema, null, true, ValueException::class);

    $this->checkVerifix($schema, "", false, "", true, true, true, true);
    $this->checkVerifix($schema, "", true, "", true, true, true, true);

    $this->checkVerifix($schema, "   ", false, "   ", true, true, true, true);
    $this->checkVerifix($schema, "   ", true, "   ", true, true, true, true);

    $this->checkVerifix($schema, "text", false, "text", true, true, true, true);
    $this->checkVerifix($schema, "text", true, "text", true, true, true, true);

    $this->checkVerifix($schema, "  text  ", false, "  text  ", true, true, true, true);
    $this->checkVerifix($schema, "  text  ", true, "  text  ", true, true, true, true);

    $this->checkVerifix($schema, false, false, null, true, false, true, true);
    $this->checkVerifix($schema, false, true, null, true, false, true, true);

    $this->checkVerifix($schema, true, false, true, true, true, true, false);
    $this->checkVerifix($schema, true, true, "1", true, true, true, false);

    $this->checkVerifix($schema, 42, false, 42, true, true, true, false);
    $this->checkVerifix($schema, 42, true, "42", true, true, true, false);

    $this->checkVerifix($schema, [], false, [], true, true, false, false);
    $this->checkException($schema, [], true, ValueException::class);

    ## Tester nullable
    $schema = new ScalarSchema("?rawstring");

    $this->checkVerifix($schema, null, false, null, true, true, true, true);
    $this->checkVerifix($schema, null, true, null, true, true, true, true);

    ## Tester required
    $schema = new ScalarSchema(["rawstring", "required" => true]);

    $this->checkVerifix($schema, false, false, null, true, false, false, false);
    $this->checkException($schema, false, true, ValueException::class);

    ## Tester allow_empty === false
    $inputParams = ["allow_empty" => false];
    $schema = new ScalarSchema("rawstring");

    $this->checkVerifix($schema, null, false, null, true, true, false, false, $inputParams);
    $this->checkException($schema, null, true, ValueException::class, $inputParams);

    $this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
    $this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);

    $schema = new ScalarSchema("?rawstring");

    $this->checkVerifix($schema, null, false, null, true, true, true, true, $inputParams);
    $this->checkVerifix($schema, null, true, null, true, true, true, true, $inputParams);

    $this->checkVerifix($schema, "", false, null, true, false, true, true, $inputParams);
    $this->checkVerifix($schema, "", true, null, true, false, true, true, $inputParams);
  }

  function testString() {
    $schema = new ScalarSchema("string");

    $this->checkVerifix($schema, null, false, null, true, true, false, false);
    $this->checkException($schema, null, true, ValueException::class);

    $this->checkVerifix($schema, "", false, "", true, true, true, true);
    $this->checkVerifix($schema, "", true, "", true, true, true, true);

    $this->checkVerifix($schema, "   ", false, "", true, true, true, false);
    $this->checkVerifix($schema, "   ", true, "", true, true, true, true);

    $this->checkVerifix($schema, "text", false, "text", true, true, true, true);
    $this->checkVerifix($schema, "text", true, "text", true, true, true, true);

    $this->checkVerifix($schema, "  text  ", false, "text", true, true, true, false);
    $this->checkVerifix($schema, "  text  ", true, "text", true, true, true, true);

    $this->checkVerifix($schema, false, false, null, true, false, true, true);
    $this->checkVerifix($schema, false, true, null, true, false, true, true);

    $this->checkVerifix($schema, true, false, true, true, true, true, false);
    $this->checkVerifix($schema, true, true, "1", true, true, true, false);

    $this->checkVerifix($schema, 42, false, 42, true, true, true, false);
    $this->checkVerifix($schema, 42, true, "42", true, true, true, false);

    $this->checkVerifix($schema, [], false, [], true, true, false, false);
    $this->checkException($schema, [], true, ValueException::class);

    ## Tester nullable
    $schema = new ScalarSchema("?string");

    $this->checkVerifix($schema, null, false, null, true, true, true, true);
    $this->checkVerifix($schema, null, true, null, true, true, true, true);

    ## Tester required
    $schema = new ScalarSchema(["string", "required" => true]);

    $this->checkVerifix($schema, false, false, null, true, false, false, false);
    $this->checkException($schema, false, true, ValueException::class);
  }

  function testInt() {
    $schema = new ScalarSchema("int");

    $this->checkVerifix($schema, null, false, null, true, true, false, false);
    $this->checkException($schema, null, true, ValueException::class);

    $this->checkVerifix($schema, 42, false, 42, true, true, true, true);
    $this->checkVerifix($schema, 42, true, 42, true, true, true, true);

    $this->checkVerifix($schema, "42", false, "42", true, true, true, false);
    $this->checkVerifix($schema, "42", true, 42, true, true, true, false);

    $this->checkVerifix($schema, "42.5", false, "42.5", true, true, true, false);
    $this->checkVerifix($schema, "42.5", true, 42, true, true, true, false);

    $this->checkVerifix($schema, "42,5", false, "42,5", true, true, true, false);
    $this->checkVerifix($schema, "42,5", true, 42, true, true, true, false);

    $this->checkVerifix($schema, "  42  ", false, "42", true, true, true, false);
    $this->checkVerifix($schema, "  42  ", true, 42, true, true, true, false);

    $this->checkVerifix($schema, "", false, "", true, true, false, false);
    $this->checkException($schema, "", true, ValueException::class);

    $this->checkVerifix($schema, "   ", false, "   ", true, true, false, false);
    $this->checkException($schema, "   ", true, ValueException::class);

    $this->checkVerifix($schema, "text", false, "text", true, true, false, false);
    $this->checkException($schema, "text", true, ValueException::class);

    $this->checkVerifix($schema, false, false, null, true, false, true, true);
    $this->checkVerifix($schema, false, true, null, true, false, true, true);

    $this->checkVerifix($schema, true, false, true, true, true, true, false);
    $this->checkVerifix($schema, true, true, 1, true, true, true, false);

    $this->checkVerifix($schema, [], false, [], true, true, false, false);
    $this->checkException($schema, [], true, ValueException::class);

    ## Tester nullable
    $schema = new ScalarSchema("?int");

    $this->checkVerifix($schema, null, false, null, true, true, true, true);
    $this->checkVerifix($schema, null, true, null, true, true, true, true);

    ## Tester required
    $schema = new ScalarSchema(["int", "required" => true]);

    $this->checkVerifix($schema, false, false, null, true, false, false, false);
    $this->checkException($schema, false, true, ValueException::class);
  }
}