<?php
declare(strict_types=1);

namespace App\Model\Table;

use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class ChangeRequestsTable extends Table
{
    public const ACTIONS  = ['add', 'edit'];
    public const STATUSES = ['pending', 'approved', 'rejected'];

    public function initialize(array $config): void
    {
        parent::initialize($config);

        $this->setTable('change_requests');
        $this->setDisplayField('id');
        $this->setPrimaryKey('id');
        $this->getSchema()
            ->setColumnType('before_json', 'json')
            ->setColumnType('after_json', 'json');

        // Use JSON type for payload (CakePHP 5 has native json type; no TypeFactory needed)
        $this->getSchema()->setColumnType('payload', 'json');

        // Timestamp behavior (your table uses created/modified columns)
        $this->addBehavior('Timestamp', [
            'events' => [
                'Model.beforeSave' => [
                    'created'  => 'new',
                    'modified' => 'always',
                ],
            ],
        ]);

        // Associations
        $this->belongsTo('Users', [
            'foreignKey' => 'user_id',
            'joinType'   => 'INNER',
        ]);

        $this->belongsTo('Faqs', [
            'foreignKey' => 'faq_id',
            'joinType'   => 'LEFT',
        ]);

        $this->belongsTo('ReviewedByUser', [
            'className'  => 'Users',
            'foreignKey' => 'reviewed_by',
            'joinType'   => 'LEFT',
        ]);
    }

    public function validationDefault(Validator $validator): Validator
    {
        $validator
            ->integer('user_id')
            ->requirePresence('user_id', 'create')
            ->notEmptyString('user_id');

        $validator
            ->scalar('action')
            ->requirePresence('action', 'create')
            ->notEmptyString('action')
            ->inList('action', self::ACTIONS, 'Invalid action.');

        // faq_id optional in general; required when action=edit
        $validator
            ->integer('faq_id')
            ->allowEmptyString('faq_id');

        $validator->add('faq_id', 'requiredForEdit', [
            'rule' => function ($value, $context) {
                $action = $context['data']['action'] ?? null;
                return $action !== 'edit' || !empty($value);
            },
            'message' => 'faq_id is required when action is "edit".',
        ]);

        // payload can be null/array/string; if string, must be valid JSON
        $validator->allowEmptyString('payload');
        $validator->add('payload', 'validJson', [
            'rule' => function ($value) {
                if ($value === null || $value === '' || is_array($value)) {
                    return true;
                }
                if (is_string($value)) {
                    json_decode($value);
                    return json_last_error() === JSON_ERROR_NONE;
                }
                return false;
            },
            'message' => 'payload must be valid JSON.',
        ]);

        $validator
            ->scalar('status')
            ->notEmptyString('status')
            ->inList('status', self::STATUSES, 'Invalid status.');

        $validator
            ->integer('reviewed_by')
            ->allowEmptyString('reviewed_by');

        $validator
            ->dateTime('reviewed_at')
            ->allowEmptyDateTime('reviewed_at');

        return $validator;
    }

    public function buildRules(RulesChecker $rules): RulesChecker
    {
        $rules->add($rules->existsIn(['user_id'], 'Users'), ['errorField' => 'user_id']);
        $rules->add($rules->existsIn(['faq_id'], 'Faqs'), ['errorField' => 'faq_id']);
        $rules->add($rules->existsIn(['reviewed_by'], 'ReviewedByUser'), ['errorField' => 'reviewed_by']);

        return $rules;
    }
}
