<?php

namespace App\Models;

use CodeIgniter\Model;
use App\Libraries\Log\Log;
use App\Entities\CommonEntity;

abstract class CommonModel extends Model
{
    protected $DBGroup          = 'default';
    // protected $table            = 'user';
    protected $primaryKey       = 'uid';
    protected $useAutoIncrement = true;
    protected $insertID         = 0;
    protected $returnType       = 'array'; //object,array,entity명::class
    protected $useSoftDeletes   = false;
    protected $protectFields    = true;
    protected $allowedFields    = [];

    // Dates
    protected $useTimestamps = true;
    protected $dateFormat    = 'datetime';
    protected $createdField  = 'created_at';
    protected $updatedField  = 'updated_at';
    protected $deletedField  = 'deleted_at';

    protected $validationRules      = [];
    protected $validationMessages   = [];
    protected $skipValidation       = false;
    protected $cleanValidationRules = true;

    // Callbacks
    protected $allowCallbacks = true;
    protected $beforeInsert   = [];
    protected $afterInsert    = [];
    protected $beforeUpdate   = [];
    protected $afterUpdate    = [];
    protected $beforeFind     = [];
    protected $afterFind      = [];
    protected $beforeDelete   = [];
    protected $afterDelete    = [];

    abstract public function getEntityByField($field, $value): ?CommonEntity;
    abstract public function getEntity($uid): ?CommonEntity;
    abstract public function getFieldFormOptions(): array;

    //참고:https://www.delftstack.com/howto/php/php-uuid/#create-a-function-to-generate-v5-uuid-in-php
    // $v5_uuid = getUUIDv5_CommonTrait('8fc990b07418d5826d98de952cfb268dee4a23a3', 'delftstack!');
    final public function getUUIDv5_CommonTrait()
    {
        $n_hex = str_replace(array('-', '{', '}'), '', UUIDS['NAMESPACE']); // Getting hexadecimal components of namespace
        $binray_str = ''; // Binary value string
        //Namespace UUID to bits conversion
        for ($i = 0; $i < strlen($n_hex); $i += 2) {
            $binray_str .= chr(hexdec($n_hex[$i] . $n_hex[$i + 1]));
        }
        //hash value
        $hashing = sha1($binray_str . UUIDS['SECRET']);

        return sprintf(
            '%08s-%04s-%04x-%04x-%12s',
            // 32 bits for the time_low
            substr($hashing, 0, 8),
            // 16 bits for the time_mid
            substr($hashing, 8, 4),
            // 16 bits for the time_hi,
            (hexdec(substr($hashing, 12, 4)) & 0x0fff) | 0x5000,
            // 8 bits and 16 bits for the clk_seq_hi_res,
            // 8 bits for the clk_seq_low,
            (hexdec(substr($hashing, 16, 4)) & 0x3fff) | 0x8000,
            // 48 bits for the node
            substr($hashing, 20, 12)
        );
    }
    final protected function create_process($entity)
    {
        //primaryKey 할당
        if ($this->useAutoIncrement === false) {
            $pk = $this->primaryKey;
            $entity->$pk = $this->getUUIDv5_CommonTrait();
        }
        if (!$this->save($entity)) {
            Log::add("error", __FUNCTION__ . "에서 호출:" . $this->getLastQuery());
            Log::add("error", implode("\n", $this->errors()));
            throw new \Exception(__FUNCTION__ . " 오류 발생.\n" . var_export($this->errors(), true));
        }
        //primaryKey 할당
        if ($this->useAutoIncrement === true) {
            $pk = $this->primaryKey;
            $entity->$pk = $this->insertID();
        }
        return $entity;
    }
    final protected function modify_process($entity)
    {
        if ($entity->hasChanged()) {
            if (!$this->save($entity)) {
                Log::add("error", __FUNCTION__ . "에서 호출:" . $this->getLastQuery());
                Log::add("error", implode("\n", $this->errors()));
                throw new \Exception(__FUNCTION__ . " 오류 발생.\n" . var_export($this->errors(), true));
            }
        } else {
            throw new \Exception(__FUNCTION__ . " 오류 발생.\n 기존정보와 동일하여 수정되지 않았습니다.");
        }
        return $entity;
    }

    //Index관련
    public function setIndexWordFilter(string $word)
    {
    }
    public function setIndexDateFilterTrit($start, $end)
    {
        $this->where('created_at >=', $start);
        $this->where('created_at <=', $end);
    }
    public function setIndexOrderBy($field, $order = 'ASC')
    {
        $this->orderBy($field, $order);
    }
}
