<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\LogQueryRequest;
use App\Http\Requests\StoreAccessLogRequest;
use App\Models\AccessLog;
use App\Models\ServerResource;
use App\Models\User;
use hg\apidoc\annotation as Apidoc;
use Illuminate\Http\JsonResponse;

#[Apidoc\Title('访问日志管理')]
class AccessLogController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:api');
        $this->middleware('permission:platform.logs.view,api')->only(['index']);
        $this->middleware('permission:platform.logs.manage,api')->only(['store']);
    }

    #[Apidoc\Title('日志查询'), Apidoc\Method('GET'), Apidoc\Url('/logs')]
    public function index(LogQueryRequest $request): JsonResponse
    {
        $sortBy = $request->string('sort_by')->toString() ?: 'requested_at';
        $sortOrder = $request->string('sort_order')->toString() ?: 'desc';

        $query = AccessLog::query()->with(['user', 'serverResource', 'bastionAccount']);

        if ($request->filled('from')) {
            $query->where('requested_at', '>=', $request->date('from'));
        }

        if ($request->filled('to')) {
            $query->where('requested_at', '<=', $request->date('to'));
        }

        if ($request->filled('action')) {
            $query->where('action', 'like', '%'.$request->string('action')->toString().'%');
        }
        if ($request->filled('actions')) {
            $query->whereIn('action', $request->array('actions'));
        }

        if ($request->filled('user_id')) {
            $query->where('user_id', $request->integer('user_id'));
        }
        if ($request->filled('user_ids')) {
            $query->whereIn('user_id', $request->array('user_ids'));
        }

        if ($request->filled('server_resource_id')) {
            $query->where('server_resource_id', $request->integer('server_resource_id'));
        }
        if ($request->filled('server_resource_ids')) {
            $query->whereIn('server_resource_id', $request->array('server_resource_ids'));
        }

        if ($request->filled('protocol')) {
            $query->where('protocol', $request->string('protocol')->toString());
        }

        if ($sortBy === 'user') {
            $query->leftJoin('users', 'users.id', '=', 'access_logs.user_id')
                ->select('access_logs.*')
                ->orderBy('users.nickname', $sortOrder);
        } elseif ($sortBy === 'resource') {
            $query->leftJoin('server_resources', 'server_resources.id', '=', 'access_logs.server_resource_id')
                ->select('access_logs.*')
                ->orderBy('server_resources.name', $sortOrder);
        } elseif ($sortBy === 'account') {
            $query->leftJoin('bastion_accounts', 'bastion_accounts.id', '=', 'access_logs.bastion_account_id')
                ->select('access_logs.*')
                ->orderBy('bastion_accounts.name', $sortOrder);
        } else {
            $column = in_array($sortBy, ['id', 'requested_at', 'action', 'protocol'], true) ? $sortBy : 'requested_at';
            $query->orderBy('access_logs.'.$column, $sortOrder);
        }

        $logs = $query->paginate($request->integer('per_page', 20));
        $userIds = AccessLog::query()
            ->whereNotNull('user_id')
            ->distinct()
            ->pluck('user_id')
            ->map(fn (int $id): int => (int) $id)
            ->all();
        $serverResourceIds = AccessLog::query()
            ->whereNotNull('server_resource_id')
            ->distinct()
            ->pluck('server_resource_id')
            ->map(fn (int $id): int => (int) $id)
            ->all();

        return response()->json([
            'code' => 0,
            'message' => 'ok',
            'data' => $logs,
            'filter_options' => [
                'actions' => AccessLog::query()
                    ->whereNotNull('action')
                    ->where('action', '!=', '')
                    ->distinct()
                    ->orderBy('action')
                    ->pluck('action')
                    ->values(),
                'users' => User::query()
                    ->select(['id', 'nickname', 'email'])
                    ->whereIn('id', $userIds)
                    ->orderBy('id')
                    ->get(),
                'server_resources' => ServerResource::query()
                    ->select(['id', 'name', 'internal_ip'])
                    ->whereIn('id', $serverResourceIds)
                    ->orderBy('id')
                    ->get(),
                'protocols' => AccessLog::query()
                    ->whereNotNull('protocol')
                    ->where('protocol', '!=', '')
                    ->distinct()
                    ->orderBy('protocol')
                    ->pluck('protocol')
                    ->values(),
            ],
        ]);
    }

    #[Apidoc\Title('新增日志'), Apidoc\Method('POST'), Apidoc\Url('/logs')]
    public function store(StoreAccessLogRequest $request): JsonResponse
    {
        $log = AccessLog::query()->create($request->validated());

        return response()->json(['code' => 0, 'message' => 'ok', 'data' => $log], 201);
    }
}
