<?php
declare(strict_types=1);

namespace app\dice\helper;

use plugin\saiadmin\exception\ApiException;

/**
 * 配置类数据按渠道隔离的更新（防止 find(id) 误更新其他渠道同业务主键行）
 */
class ConfigScopeEditHelper
{
    /**
     * 在查询上附加渠道条件
     */
    public static function applyDeptIdWhere($query, int $deptId, string $column = 'dept_id'): void
    {
        if (AdminScopeHelper::isTemplateDeptId($deptId)) {
            $query->where(function ($q) use ($deptId, $column) {
                $q->where($column, $deptId);
                if (method_exists($q, 'orWhereNull')) {
                    $q->orWhereNull($column);
                } else {
                    $q->whereOr($column, null);
                }
            });
            return;
        }
        $query->where($column, $deptId);
    }

    /**
     * 按主键 + 渠道更新配置行
     *
     * @param Model $model 模型实例（用于取表名、主键）
     * @param mixed $primaryKeyValue 列表/表单中的主键值
     * @param int $deptId 渠道 ID（0=默认模板）
     * @param array $data 更新字段
     * @param array $forbidden 禁止写入的字段名
     */
    /**
     * 按主键更新（主键全局唯一表如 dice_lottery_pool_config）
     * 以库中记录的 dept_id 为准，避免请求未带 dept_id 时误按默认模板 0 查找失败
     */
    public static function updateByPkAndDept(
        object $model,
        $primaryKeyValue,
        int $requestDeptId,
        array $data,
        array $forbidden = ['id', 'dept_id', 'create_time', 'update_time', 'delete_time', 'row_id'],
        ?array $adminInfo = null,
        $rawRequestDeptId = null
    ): bool {
        foreach ($forbidden as $field) {
            unset($data[$field]);
        }
        if ($data === []) {
            return true;
        }

        $pk = self::resolvePk($model);
        $record = $model->where($pk, $primaryKeyValue)->find();
        if ($record === null) {
            throw new ApiException('data not found');
        }

        $recordDeptId = AdminScopeHelper::normalizeRecordDeptId(
            is_array($record) ? ($record['dept_id'] ?? null) : ($record->dept_id ?? null)
        );

        if ($adminInfo !== null && ! AdminScopeHelper::canAccessDept($adminInfo, $recordDeptId, $rawRequestDeptId)) {
            throw new ApiException('no permission to update this record');
        }

        if ($rawRequestDeptId !== null && $rawRequestDeptId !== '') {
            $targetDeptId = AdminScopeHelper::resolveConfigDeptId($adminInfo, $rawRequestDeptId);
            if ($targetDeptId !== $recordDeptId) {
                throw new ApiException('record does not belong to selected channel');
            }
        }

        $query = $model->where($pk, $primaryKeyValue);
        self::applyDeptIdWhere($query, $recordDeptId);

        $affected = $query->update($data);
        return $affected !== false;
    }

    /**
     * dice_reward_config / dice_config：业务 id（0～25 等）+ 渠道更新
     */
    public static function updateByBusinessIdAndDept(
        object $model,
        int $businessId,
        int $deptId,
        array $data,
        array $forbidden = ['id', 'dept_id', 'create_time', 'update_time', 'delete_time', 'row_id']
    ): bool {
        foreach ($forbidden as $field) {
            unset($data[$field]);
        }
        if ($data === []) {
            return true;
        }

        $query = $model->where('id', $businessId);
        self::applyDeptIdWhere($query, $deptId);

        $record = (clone $query)->find();
        if ($record === null) {
            throw new ApiException('config id=' . $businessId . ' not found for current channel');
        }

        $affected = $query->update($data);
        return $affected !== false;
    }

    /**
     * 列表/读取：按主键 + 渠道取单条（避免 find(pk) 命中其他渠道）
     */
    private static function resolvePk(object $model): string
    {
        if (method_exists($model, 'getPk')) {
            return (string) $model->getPk();
        }
        if (method_exists($model, 'getKeyName')) {
            return (string) $model->getKeyName();
        }
        return 'id';
    }

    public static function findByPkAndDept(object $model, $primaryKeyValue, int $deptId)
    {
        $pk = self::resolvePk($model);
        $query = $model->where($pk, $primaryKeyValue);
        self::applyDeptIdWhere($query, $deptId);
        return $query->find();
    }
}
