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

use nulib\cl;
use nulib\php\func;

class Registry {
  const TYPES = [
    "rawstring" => trawstring::class,
    "string" => tstring::class,
    "text" => ttext::class,
    "bool" => tbool::class, "boolean" => tbool::class,
    "int" => tint::class, "integer" => tint::class,
    "float" => tfloat::class, "flt" => tfloat::class,
    "double" => tfloat::class, "dbl" => tfloat::class,
    "array" => tarray::class,
    "callable" => tcallable::class,
    # types spéciaux
    "raw" => tmixed::class,
    "mixed" => tmixed::class,
    "key" => tkey::class,
    "pkey" => tpkey::class,
    "content" => tcontent::class,
  ];

  function __construct() {
    $this->types = [];
  }

  /** @var IType[] */
  protected $types;

  function get(bool $nullable, ?string $name, ?array $args=null, ?array $definition=null): IType {
    $name ??= "raw";
    $class = self::TYPES[$name];
    if (cl::is_list($args)) {
      $key = array_key_last($args);
      $params = $args[$key];
      unset($args[$key]);
    } else {
      $params = $args;
      $args = null;
    }
    $params = cl::merge($class::get_params_from_definition($definition), $params);
    if ($args || $params !== null) {
      $args ??= [];
      return func::with([$class, false, ...$args, $nullable, $params])->invoke();
    }
    if ($nullable) $name = "?$name";
    $type = cl::get($this->types, $name);
    if ($type === null) $type = $this->types[$name] = new $class($nullable);
    return $type;
  }
}
