<?php

declare(strict_types=1);

namespace app\admin\model;

use Throwable;
use app\admin\library\Auth;
use app\common\model\traits\TimestampInteger;
use support\think\Model;
use Webman\Http\Request;

/**
 * AdminLog 模型（Webman 迁移版）
 */
class AdminLog extends Model
{
    use TimestampInteger;

    protected string $table = 'admin_log';
    protected string $pk = 'id';
    protected bool $autoWriteTimestamp = true;
    protected bool $updateTime = false;

    protected string $title = '';
    /** 日志内容（勿用 $data，会与 ThinkORM Model 的 data 选项冲突） */
    protected string|array $logData = '';
    protected array $urlIgnoreRegex = [
        '/^(.*)\/(select|index|logout)$/i',
    ];
    protected array $desensitizationRegex = [
        '/(password|salt|token)/i'
    ];

    public static function instance(?Request $request = null): self
    {
        $request = $request ?? (function_exists('request') ? request() : null);
        if ($request !== null && isset($request->adminLog) && $request->adminLog instanceof self) {
            return $request->adminLog;
        }
        $log = new static();
        if ($request !== null) {
            $request->adminLog = $log;
        }
        return $log;
    }

    public function setTitle(string $title): void
    {
        $this->title = $title;
    }

    /** 设置日志内容（BuildAdmin 控制器调用） */
    public function setLogData(string|array $data): void
    {
        $this->logData = $data;
    }

    public function setUrlIgnoreRegex(array|string $regex = []): void
    {
        $this->urlIgnoreRegex = array_merge($this->urlIgnoreRegex, is_array($regex) ? $regex : [$regex]);
    }

    public function setDesensitizationRegex(array|string $regex = []): void
    {
        $this->desensitizationRegex = array_merge($this->desensitizationRegex, is_array($regex) ? $regex : [$regex]);
    }

    protected function desensitization(array|string $data): array|string
    {
        if (!is_array($data) || !$this->desensitizationRegex) {
            return $data;
        }
        foreach ($data as $index => &$item) {
            foreach ($this->desensitizationRegex as $reg) {
                if (preg_match($reg, (string) $index)) {
                    $item = '***';
                } elseif (is_array($item)) {
                    $item = $this->desensitization($item);
                }
            }
        }
        return $data;
    }

    public function record(string $title = '', string|array|null $data = null, ?Request $request = null): void
    {
        $request = $request ?? (function_exists('request') ? request() : null);
        if (!$request) {
            return;
        }

        $auth = Auth::instance();
        $adminId = $auth->isLogin() ? $auth->id : 0;
        $username = $auth->isLogin() ? $auth->username : ($request->get('username') ?? $request->post('username') ?? __('Unknown'));

        $controllerPath = get_controller_path($request) ?? '';
        $pathParts = explode('/', trim($request->path(), '/'));
        $action = $pathParts[array_key_last($pathParts)] ?? '';
        $path = $controllerPath . ($action ? '/' . $action : '');

        foreach ($this->urlIgnoreRegex as $item) {
            if (preg_match($item, $path)) {
                return;
            }
        }

        $data = $data ?: $this->logData;
        if (!$data) {
            $data = array_merge($request->get(), $request->post());
        }
        $data = $this->desensitization($data);
        $title = $title ?: $this->title;
        if (!$title && class_exists(\app\admin\model\AdminRule::class)) {
            $controllerTitle = \app\admin\model\AdminRule::where('name', $controllerPath)->value('title');
            $pathTitle = \app\admin\model\AdminRule::where('name', $path)->value('title');
            $title = $pathTitle ?: __('Unknown') . '(' . $action . ')';
            $title = $controllerTitle ? ($controllerTitle . '-' . $title) : $title;
        }
        if (!$title) {
            $title = __('Unknown');
        }

        $url = $request->url();
        $url = strlen($url) > 1500 ? substr($url, 0, 1500) : $url;
        $useragent = $request->header('user-agent', '');
        $useragent = strlen($useragent) > 255 ? substr($useragent, 0, 255) : $useragent;

        self::create([
            'admin_id'  => $adminId,
            'username'  => $username,
            'url'       => $url,
            'title'     => $title,
            'data'      => !is_scalar($data) ? json_encode($data, JSON_UNESCAPED_UNICODE) : $data,
            'ip'        => $request->getRealIp(),
            'useragent' => $useragent,
        ]);
    }

    public function admin()
    {
        return $this->belongsTo(Admin::class);
    }
}
