<?php

declare(strict_types=1);

namespace Kylin\Education\Traits;

use Illuminate\Support\Facades\Crypt;

/**
 * 敏感字段加密 Trait
 *
 * 依据《中华人民共和国个人信息保护法》第二十八条：
 * 不满十四周岁未成年人的个人信息属于敏感个人信息。
 *
 * 依据《个人信息保护法》第五十一条：
 * 采取加密、去标识化等安全技术措施。
 *
 * 依据《未成年人保护法》第七十二条：
 * 处理未成年人个人信息需取得监护人同意，敏感信息需加密存储。
 *
 * 自动加密/解密标记的敏感字段：
 *  - 写入时自动 AES-256 加密
 *  - 读取时自动解密
 *  - 解密失败时返回原始值（容错处理）
 */
trait Encryptable
{
    /**
     * 获取需要加密的字段列表
     *
     * @return array
     */
    public function getEncryptableFields(): array
    {
        return property_exists($this, 'encryptable') ? $this->encryptable : [];
    }

    /**
     * 获取属性值（解密加密字段）
     *
     * @param string $key
     * @return mixed
     */
    public function getAttributeValue($key): mixed
    {
        $value = parent::getAttributeValue($key);

        if (in_array($key, $this->getEncryptableFields(), true) && $value !== null && is_string($value)) {
            try {
                return Crypt::decryptString($value);
            } catch (\Exception) {
                return $value;
            }
        }

        return $value;
    }

    /**
     * 设置属性值（加密加密字段）
     *
     * @param string $key
     * @param mixed  $value
     * @return mixed
     */
    public function setAttribute($key, $value): mixed
    {
        if (in_array($key, $this->getEncryptableFields(), true) && $value !== null && is_string($value) && $value !== '') {
            $value = Crypt::encryptString($value);
        }

        return parent::setAttribute($key, $value);
    }
}