<?php
namespace nur\m\cli;

use nur\A;
use nur\b\ValueException;
use nur\cli\Application;
use nur\data\types\Metadata;

abstract class UpdateMigrationsApp extends Application {
  function trace(string $line): void {
    echo "$line\n";
  }

  /**
   * @var string répertoire de base pour la génération des fichiers (i.e chemin
   * du projet) 
   */
  const BASEDIR = null;

  /** @var Metadata */
  private static $database_md;

  private static function database_md(): Metadata {
    if (self::$database_md === null) {
      self::$database_md = new Metadata([
        "class" => ["?string", null, "classe de migration qui contient les définitions"],
        "sql_dir" => ["?string", null, "chemin relatif dans lequel générer les migrations SQL e.g. 'config/sqlmig/DATABASE'"],
        "sql_prefix" => ["bool", null, ""],
        "doc_dir" => ["?string", null, "chemin relatif dans lequel générer la doc e.g. 'doc'"],
        "class_dir" => ["?string", null, "chemin relatif dans lequel générer les classes de DAO e.g. 'src/m'"],
        "class_package" => ["?string", null, "package des classes DAO, exprimé relativement au package de la classe qui contient les définitions"],
        "class_baserow" => ["?string", null, "classe de base pour les classes DAO"],
      ]);
    }
    return self::$database_md;
  }

  /** @var array base de données dont il faut faire la migration */
  const DATABASE = null;
  /**
   * @var array liste des bases de données supplémentaires dont il faut faire la
   * migration
   */
  const DATABASES = null;

  /** @var bool valeur par défaut de $doSql si aucun argument n'est spécifié */
  const DO_SQL = true;

  /** @var bool valeur par défaut de $doClass si aucun argument n'est spécifié */
  const DO_CLASS = true;

  /** @var bool valeur par défaut de $doDoc si aucun argument n'est spécifié */
  const DO_DOC = true;

  const MIGRATE_PARAMS_SCHEMA = [
    "basedir" => ["?string", null, "chemin absolu du projet"],
    "overwrite" => ["?bool", null, "faut-il regénérer les fichier?"],
    "verbose" => ["bool", null, "faut-il activer l'affichage verbeux"],
    "class" => ["?string", null, "cf database_schema"],
    "do_sql" => ["bool", null, "faut-il générer les fichiers SQL"],
    "sql_dir" => ["?string", null, "cf database_schema"],
    "sql_prefix" => ["bool", null, "cf database_schema"],
    "class_dir" => ["?string", null, "cf database_schema"],
    "class_package" => ["?string", null, "cf database_schema"],
    "class_baserow" => ["?string", null, "cf database_schema"],
    "do_doc" => ["bool", null, "faut-il générer la documentation"],
    "doc_dir" => ["?string", null, "cf database_schema"],
    "do_class" => ["bool", null, "faut-il générer les classes DAO"],
  ];

  protected abstract function migrate(array $params);

  const ARGS = [
    ["group",
      ["-o", "--overwrite", "name" => "overwrite", "value" => true,
        "help" => "forcer (resp. interdire) l'écrasement des fichier générés",
      ],
      ["-k", "--keep", "name" => "overwrite", "value" => false],
    ],
    ["-v", "--verbose", "name" => "verbose", "value" => true,
      "help" => "mode verbeux",
    ],
    ["-b", "--basedir", "arg" => "dir",
      "help" => "répertoire de base pour la génération des fichiers",
    ],
    ["-s", "--sql-only", "name" => "do_sql", "value" => true,
      "help" => "ne faire que la génération des fichiers SQL",
    ],
    ["-c", "--class-only", "name" => "do_class", "value" => true,
      "help" => "ne faire que la génération des fichiers DAO",
    ],
    ["-d", "--doc-only", "name" => "do_doc", "value" => true,
      "help" => "ne faire que la génération de la documentation",
    ],
    ["group",
      ["-l", "--select", "arg" => "value", "name" => "select",
        "help" => "sélectionner une base de données en particulier"
      ],
      ["-1", "--first", "name" => "select", "value" => 1],
      ["-2", "--second", "name" => "select", "value" => 2],
    ],
  ];

  /** @var ?string */
  protected $overwrite = null;
  protected $verbose = false;
  protected $basedir;
  protected $doSql = null;
  protected $doClass = null;
  protected $doDoc = null;
  protected $select;

  function main() {
    $overwrite = $this->overwrite;
    $verbose = $this->verbose;
    $basedir = $this->basedir;
    if ($basedir === null) $basedir = static::BASEDIR;
    if ($basedir === null) throw new ValueException("Vous devez spécifier --basedir");

    $doSql = $this->doSql;
    $doClass = $this->doClass;
    $doDoc = $this->doDoc;
    if ($doSql === null && $doDoc === null && $doClass === null) {
      $doSql = static::DO_SQL;
      $doClass = static::DO_CLASS;
      $doDoc = static::DO_DOC;
    }

    $databases = [];
    A::append_nn($databases, static::DATABASE);
    A::merge_nn($databases, static::DATABASES);
    $select = $this->select;
    if ($select !== null) {
      if (is_numeric($select)) {
        $index = $select - 1;
        $database = A::nth($databases, $index);
        if ($database === null) throw new ValueException("$select: index invalide");
      } else {
        $database = A::get($databases, $select);
        if ($database === null) throw new ValueException("$select: base de donnée invalide");
      }
      $databases = [$database];
    }
    self::database_md()->eachEnsureSchema($databases);

    foreach ($databases as $database) {
      $this->migrate([
        "class" => $database["class"],
        "overwrite" => $overwrite,
        "verbose" => $verbose,
        "basedir" => $basedir,
        "do_sql" => $doSql,
        "sql_dir" => $database["sql_dir"],
        "sql_prefix" => $database["sql_prefix"],
        "do_class" => $doClass,
        "class_dir" => $database["class_dir"],
        "class_package" => $database["class_package"],
        "class_baserow" => $database["class_baserow"],
        "do_doc" => $doDoc,
        "doc_dir" => $database["doc_dir"],
      ]);
    }
  }
}
