<?php

namespace App\Models;

use CodeIgniter\Model;
use App\Libraries\LogCollector;

abstract class CommonModel extends Model
{
    protected $table = '';
    protected $primaryKey = '';
    protected $useAutoIncrement = true;
    // protected $returnType = 'array';
    protected $useSoftDeletes = false;
    protected $protectFields = true;
    protected $allowedFields = [];

    protected bool $allowEmptyInserts = false;
    protected bool $updateOnlyChanged = true;

    protected array $casts = [];
    protected array $castHandlers = [];

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

    // Validation
    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 = [];

    protected function __construct()
    {
        parent::__construct();
    }
    final public function getTable(): string
    {
        return constant("static::TABLE");
    }
    final public function getPKField(): string
    {
        return constant("static::PK");
    }
    final public function getTitleField(): string
    {
        return constant("static::TITLE");
    }
    //Primary Key로 uuid를 사용시 해당 모델에 아래 변수 반드시 추가 필요
    // protected $useAutoIncrement = false;
    // protected $beforeInsert = ['generateUUID'];
    // allowedFields에는 PK넣으면 않됨, Column Type: CHAR(36)
    // 
    final protected function generateUUID(): string
    {
        $data = random_bytes(16);
        // UUID version 4 (random)
        $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // version 0100
        $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // variant 10
        return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
    }
    public function getFormFieldRule(string $action, string $field): string
    {
        if (is_array($field)) {
            throw new \Exception(__FUNCTION__ . "=> field가 array 입니다.\n" . var_export($field, true));
        }
        switch ($field) {
            case $this->getPKField():
                // 수동입력인 경우
                if (!$this->useAutoIncrement) {
                    $rule = "required|regex_match[/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/]";
                    $rule .= in_array($action, ["create", "create_form"]) ? "|is_unique[{$this->table}.{$field}]" : "";
                } else {
                    $rule = "required|numeric";
                }
                break;
            case $this->getTitleField():
                $rule = "required|trim|string";
                break;
            case 'picture':
                $rule = "is_image[{$field}]|mime_in[{$field},image/jpg,image/jpeg,image/gif,image/png,image/webp]|max_size[{$field},300]|max_dims[{$field},2048,768]";
                break;
            case "updated_at":
            case "created_at":
            case "deleted_at":
                $rule = "permit_empty|valid_date";
                break;
            default:
                $rule = "permit_empty|trim|string";
                break;
        }
        return $rule;
    }
    // create, modify 직전 작업용 작업
    protected function convert_process(string $action, string $field, array $formDatas): mixed
    {
        $convertedData = null;
        // 필드 값 존재 여부 확인
        $hasValue = array_key_exists($field, $formDatas);
        $value    = $hasValue ? $formDatas[$field] : null;
        switch ($field) {
            case $this->getPKField():
                // PK 값이 없으면 UUID-like 값 생성
                if (!$hasValue || empty($value)) {
                    $randomBytes = bin2hex(random_bytes(32));
                    $convertedData = sprintf(
                        '%08s-%04s-%04x-%04x-%12s',
                        substr($randomBytes, 0, 8),
                        substr($randomBytes, 8, 4),
                        substr($randomBytes, 12, 4),
                        substr($randomBytes, 16, 4),
                        substr($randomBytes, 20, 12)
                    );
                } else {
                    $convertedData = $value;
                }
                break;
            case "editor":
            case "detail":
            case "content":
            case "discription":
            case "history":
                // textarea 계열은 XSS 방지
                if ($value === '' || $value === null) {
                    $convertedData = null; // 기본적으로 null
                } elseif ($value === ' ') {
                    $convertedData = '';   // 공백 하나 → 의도적인 빈칸 저장
                } else {
                    $convertedData = htmlentities($value, ENT_QUOTES, 'UTF-8');
                }
                break;
            default:
                if ($value === '' || $value === null) {
                    if ($action === 'insert') {
                        // INSERT → unset 해서 DB default 사용
                        return null;
                    }
                    if ($action === 'update') {
                        // UPDATE → 기본은 null 처리
                        $convertedData = null;
                    }
                } elseif ($value === ' ') {
                    // 공백 하나 → 빈칸으로 저장
                    $convertedData = '';
                } else {
                    $convertedData = $value;
                }
                break;
        }
        return $convertedData;
    }

    protected function create_process(array $formDatas): mixed
    {
        $pkField = $this->getPKField();
        // primaryKey가 자동입력이 아니면
        if (!$this->useAutoIncrement) {
            $formDatas[$pkField] = $this->generateUUID();
        }
        // 최종 저장 시 오류 발생하면
        if (!$this->save($formDatas)) {
            $message = sprintf(
                "\n------%s 오류-----\n%s\n%s\n------------------------------\n",
                __METHOD__,
                var_export($this->errors(), true),
                $this->getLastQuery()
            );
            LogCollector::debug($message);
            throw new \Exception($message);
        }
        //Model별 returntype형의 Entity 호출
        if (!class_exists($this->returnType)) {
            throw new \RuntimeException(__METHOD__ . "에서 returnType: {$this->returnType}이 정의되지 않았습니다.");
        }
        $entity = new $this->returnType($formDatas);
        // primaryKey가 자동입력이면
        if ($this->useAutoIncrement) {
            $entity->$pkField = $this->getInsertID();
        }
        return $entity;
    }
    final public function create(array $formDatas): mixed
    {
        // LogCollector::debug("입력내용");
        // LogCollector::debug(var_export($formDatas, true));
        foreach (array_keys($formDatas) as $field) {
            if (array_key_exists($field, $formDatas)) {
                $formDatas[$field] = $this->convert_process(__FUNCTION__, $field, $formDatas);
            }
        }
        return $this->create_process($formDatas);
    }
    protected function modify_process(mixed $entity): mixed
    {
        // 최종 저장 시 오류 발생하면
        if (!$this->save($entity)) {
            $message = sprintf(
                "\n------%s 오류-----\n%s\n------------------------------\n",
                __METHOD__,
                var_export($this->errors(), true)
            );
            LogCollector::debug($message);
            throw new \Exception($message);
        }
        return $entity;
    }
    final public function modify(mixed $entity, array $formDatas): mixed
    {
        // 저장하기 전에 데이터 값 변경이 필요한 Field
        // LogCollector::debug("[{$entity->getPK()}/{$entity->getTitle()}] 변경 전 내용");
        // LogCollector::debug(var_export($formDatas, true));
        // LogCollector::debug(var_export($entity->toArray(), true));
        foreach (array_keys($formDatas) as $field) {
            if (array_key_exists($field, $formDatas)) {
                $entity->$field = $this->convert_process(__FUNCTION__, $field, $formDatas);
            }
        }
        //수정일추가
        $entity->setUpdatedAt(date("Y-m-d H:i:s"));
        // LogCollector::debug("[{$entity->getPK()}/{$entity->getTitle()}] 변경 후 내용");
        // LogCollector::debug(var_export($entity->toArray(), true));
        // dd($entity);
        return $this->modify_process($entity);
    }

    //List 검색용
    //FormFilter 조건절 처리
    final public function setList_FormFilter(string $field, mixed $filter_value): void {}
    //검색어조건절처리
    final public function setList_WordFilter(string $word): void {}
    //날자검색
    final public function setList_DateFilter(string $start, string $end): void {}
    //OrderBy 처리
    final public function setOrderBy(string $field, $value): void {}
}
