<?php
namespace nur\sery\db\pdo;

use DateTimeInterface;
use nur\sery\db\_private\_base;
use nur\sery\php\time\Date;
use nur\sery\php\time\DateTime;
use nur\sery\str;
use nur\sery\ValueException;

class _query_base extends _base {
  protected static function verifix(&$sql, ?array &$bindinds=null, ?array &$meta=null): void {
    if (is_array($sql)) {
      $prefix = $sql[0] ?? null;
      if ($prefix === null) {
        throw new ValueException("requête invalide");
      } elseif (_query_create::isa($prefix)) {
        $sql = _query_create::parse($sql, $bindinds);
        $meta = ["isa" => "create", "type" => "ddl"];
      } elseif (_query_select::isa($prefix)) {
        $sql = _query_select::parse($sql, $bindinds);
        $meta = ["isa" => "select", "type" => "dql"];
      } elseif (_query_insert::isa($prefix)) {
        $sql = _query_insert::parse($sql, $bindinds);
        $meta = ["isa" => "insert", "type" => "dml"];
      } elseif (_query_update::isa($prefix)) {
        $sql = _query_update::parse($sql, $bindinds);
        $meta = ["isa" => "update", "type" => "dml"];
      } elseif (_query_delete::isa($prefix)) {
        $sql = _query_delete::parse($sql, $bindinds);
        $meta = ["isa" => "delete", "type" => "dml"];
      } elseif (_query_generic::isa($prefix)) {
        $sql = _query_generic::parse($sql, $bindinds);
        $meta = ["isa" => "generic", "type" => null];
      } else {
        throw ValueException::invalid_kind($sql, "query");
      }
    } else {
      if (!is_string($sql)) $sql = strval($sql);
      if (_query_create::isa($sql)) {
        $meta = ["isa" => "create", "type" => "ddl"];
      } elseif (_query_select::isa($sql)) {
        $meta = ["isa" => "select", "type" => "dql"];
      } elseif (_query_insert::isa($sql)) {
        $meta = ["isa" => "insert", "type" => "dml"];
      } elseif (_query_update::isa($sql)) {
        $meta = ["isa" => "update", "type" => "dml"];
      } elseif (_query_delete::isa($sql)) {
        $meta = ["isa" => "delete", "type" => "dml"];
      } elseif (_query_generic::isa($sql)) {
        $meta = ["isa" => "generic", "type" => null];
      } else {
        $meta = ["isa" => "generic", "type" => null];
      }
    }
  }

  static function is_sqldate(string $date): bool {
    return preg_match('/^\d{4}-\d{2}-\d{2}(?: \d{2}:\d{2}:\d{2})?$/', $date);
  }

  protected function verifixBindings(&$value): void {
    if ($value instanceof Date) {
      $value = $value->format('Y-m-d');
    } elseif ($value instanceof DateTime) {
      $value = $value->format('Y-m-d H:i:s');
    } elseif ($value instanceof DateTimeInterface) {
      $value = $value->format('Y-m-d H:i:s');
      str::del_suffix($value, " 00:00:00");
    } elseif (is_string($value)) {
      if (self::is_sqldate($value)) {
        # déjà dans le bon format
      } elseif (Date::isa_date($value, true)) {
        $value = new Date($value);
        $value = $value->format('Y-m-d');
      } elseif (DateTime::isa_datetime($value, true)) {
        $value = new DateTime($value);
        $value = $value->format('Y-m-d H:i:s');
      }
    } elseif (is_bool($value)) {
      $value = $value? 1: 0;
    }
  }

  const DEBUG_QUERIES = false;

  function useStmt(\PDO $db, ?\PDOStatement &$stmt=null, ?string &$sql=null): bool {
    if (static::DEBUG_QUERIES) { #XXX
      error_log($this->sql);
      //error_log(var_export($this->bindings, true));
    }
    if ($this->bindings !== null) {
      $stmt = $db->prepare($this->sql);
      foreach ($this->bindings as $name => $value) {
        $this->verifixBindings($value);
        $stmt->bindValue($name, $value);
      }
      return true;
    } else {
      $sql = $this->sql;
      return false;
    }
  }
}
