<?php

declare(strict_types=1);

namespace app\common\event;

/**
 * 后台安全事件（数据回收、敏感数据记录）
 * 迁移自 app/common/event/Security.php，需 Admin、Token、DataRecycle 等模型支持
 */
class Security
{
    protected array $listenAction = ['edit', 'del'];

    /**
     * @param mixed $auth Auth 实例（backendInit 传入）
     */
    public function handle(mixed $auth): bool
    {
        $request = function_exists('request') ? request() : null;
        if (!$request) {
            return true;
        }

        $action = $this->getActionFromPath($request->path());
        if (!in_array($action, $this->listenAction)) {
            return true;
        }
        if ($action === 'del' && $request->method() !== 'POST' && $request->method() !== 'DELETE') {
            return true;
        }
        if ($action === 'edit' && $request->method() !== 'POST') {
            return true;
        }

        if (!class_exists(\app\admin\model\DataRecycle::class) || !class_exists(\app\admin\model\SensitiveData::class)) {
            return true;
        }

        if ($action === 'del') {
            return $this->handleDel($request, $auth);
        }
        return $this->handleEdit($request, $auth);
    }

    protected function getActionFromPath(string $path): string
    {
        $parts = explode('/', trim($path, '/'));
        return $parts[array_key_last($parts)] ?? '';
    }

    protected function handleDel($request, $auth): bool
    {
        $dataIds = $request->post('ids') ?? $request->get('ids');
        if (!$dataIds) {
            return true;
        }
        try {
            $controllerPath = get_controller_path($request) ?? '';
            $recycle = \app\admin\model\DataRecycle::where('status', 1)
                ->where('controller_as', $controllerPath)
                ->find();
            if (!$recycle) {
                return true;
            }
            $connection = class_exists(\ba\TableManager::class)
                ? \ba\TableManager::getConnection($recycle['connection'])
                : null;
            $db = $connection ? \support\think\Db::connect($connection) : \support\think\Db::connect();
            $recycleData = $db->name($recycle['data_table'])
                ->whereIn($recycle['primary_key'], $dataIds)
                ->select()
                ->toArray();
            $recycleDataArr = [];
            $adminId = $auth && $auth->isLogin() ? $auth->id : 0;
            foreach ($recycleData as $item) {
                $recycleDataArr[] = [
                    'admin_id'    => $adminId,
                    'recycle_id'  => $recycle['id'],
                    'data'        => json_encode($item, JSON_UNESCAPED_UNICODE),
                    'connection'  => $recycle['connection'],
                    'data_table'  => $recycle['data_table'],
                    'primary_key' => $recycle['primary_key'],
                    'ip'          => $request->getRealIp(),
                    'useragent'   => substr($request->header('user-agent', ''), 0, 255),
                ];
            }
            if ($recycleDataArr) {
                $model = new \app\admin\model\DataRecycleLog();
                $model->saveAll($recycleDataArr);
            }
        } catch (\Throwable $e) {
            \support\Log::warning('[DataSecurity] ' . $e->getMessage());
        }
        return true;
    }

    protected function handleEdit($request, $auth): bool
    {
        try {
            $controllerPath = get_controller_path($request) ?? '';
            $sensitiveData = \app\admin\model\SensitiveData::where('status', 1)
                ->where('controller_as', $controllerPath)
                ->find();
            if (!$sensitiveData) {
                return true;
            }
            $sensitiveData = $sensitiveData->toArray();
            $dataId = $request->post($sensitiveData['primary_key']) ?? $request->get($sensitiveData['primary_key']);
            $connection = class_exists(\ba\TableManager::class)
                ? \ba\TableManager::getConnection($sensitiveData['connection'])
                : null;
            $db = $connection ? \support\think\Db::connect($connection) : \support\think\Db::connect();
            $editData = $db->name($sensitiveData['data_table'])
                ->field(array_keys($sensitiveData['data_fields']))
                ->where($sensitiveData['primary_key'], $dataId)
                ->find();
            if (!$editData) {
                return true;
            }
            $newData = $request->post();
            $sensitiveDataLog = [];
            foreach ($sensitiveData['data_fields'] as $field => $title) {
                if (isset($editData[$field]) && isset($newData[$field]) && $editData[$field] != $newData[$field]) {
                    $newVal = $newData[$field];
                    if (stripos($field, 'password') !== false && $newVal) {
                        $newVal = '******';
                    }
                    $sensitiveDataLog[] = [
                        'admin_id'     => $auth && $auth->isLogin() ? $auth->id : 0,
                        'sensitive_id' => $sensitiveData['id'],
                        'connection'   => $sensitiveData['connection'],
                        'data_table'   => $sensitiveData['data_table'],
                        'primary_key'  => $sensitiveData['primary_key'],
                        'data_field'   => $field,
                        'data_comment' => $title,
                        'id_value'     => $dataId,
                        'before'       => $editData[$field],
                        'after'        => $newVal,
                        'ip'           => $request->getRealIp(),
                        'useragent'    => substr($request->header('user-agent', ''), 0, 255),
                    ];
                }
            }
            if ($sensitiveDataLog) {
                $model = new \app\admin\model\SensitiveDataLog();
                $model->saveAll($sensitiveDataLog);
            }
        } catch (\Throwable $e) {
            \support\Log::warning('[DataSecurity] ' . $e->getMessage());
        }
        return true;
    }
}
