<?php
declare(strict_types=1);

namespace App\Model\Table;

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

class RoleFeatureSettingsTable extends Table
{
    public function initialize(array $config): void
    {
        parent::initialize($config);

        $this->setTable('role_feature_settings');
        $this->setPrimaryKey('id');
        $this->setDisplayField('id');

        $this->belongsTo('Features', [
            'foreignKey' => 'feature_id',
            'joinType'   => 'INNER',
        ]);
    }

    public function validationDefault(Validator $validator): Validator
    {
        $validator->inList('role', ['admin','clinician']);
        $validator->boolean('visible');
        $validator->integer('feature_id');

        return $validator;
    }

    public function saveVisibilityForRole(string $role, array $flags): bool
    {
        if (!in_array($role, ['admin','clinician'], true)) {
            return false;
        }

        if ($flags && array_keys($flags) === range(0, count($flags) - 1)) {
            $flags = array_fill_keys($flags, 1);
        }

        $Features = $this->getAssociation('Features')->getTarget();
        $valid = $Features->find('list', [
            'keyField'   => 'key',
            'valueField' => 'id',
        ])->toArray();

        if (!$valid) {
            return true;
        }

        $normalized = [];
        foreach ($valid as $key => $fid) {
            $normalized[$key] = !empty($flags[$key]) ? 1 : 0;
        }

        return $this->getConnection()->transactional(function () use ($role, $valid, $normalized) {
            foreach ($valid as $key => $fid) {
                $row = $this->find()
                    ->where(['role' => $role, 'feature_id' => $fid])
                    ->first();

                if (!$row) {
                    $row = $this->newEntity([
                        'role'       => $role,
                        'feature_id' => $fid,
                    ]);
                }

                $row = $this->patchEntity($row, ['visible' => (int)$normalized[$key]]);
                if (!$this->save($row)) {
                    return false;
                }
            }
            return true;
        });
    }

    public function visibleMapForRole(string $role): array
    {
        $Features = $this->getAssociation('Features')->getTarget();

        // 所有 feature
        $all = $Features->find()
            ->select(['id','key'])
            ->enableHydration(false)
            ->toArray();

        if (!$all) {
            return [];
        }

        $map = [];
        foreach ($all as $f) {
            $map[$f['key']] = true;
        }

        $rows = $this->find()
            ->select(['feature_id','visible'])
            ->where(['role' => $role])
            ->enableHydration(false)
            ->toArray();

        $id2key = [];
        foreach ($all as $f) {
            $id2key[$f['id']] = $f['key'];
        }

        foreach ($rows as $r) {
            $key = $id2key[$r['feature_id']] ?? null;
            if ($key !== null) {
                $map[$key] = (bool)$r['visible'];
            }
        }

        return $map;
    }

    public function getVisibleMapForRole(string $role): array
    {
        return $this->visibleMapForRole($role);
    }
}
