<?php

declare(strict_types=1);

namespace PortalPeople\monitor\controllers\web;

use PortalPeople\monitor\services\MonitorService;
use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\web\ForbiddenHttpException;
use yii\web\Response;

/**
 * Monitor Web Controller
 *
 * Backend HTML dashboard with AJAX JSON endpoints for polling.
 * Requires an active session and Global Admins group membership.
 *
 * Routes (registered by Module::bootstrap() for the backend app):
 *   GET monitor          → actionIndex  (HTML dashboard)
 *   GET monitor/all      → actionAll    (JSON — AJAX polling)
 *   GET monitor/health   → actionHealth (JSON)
 *   GET monitor/queues   → actionQueues (JSON)
 *   GET monitor/db       → actionDb     (JSON)
 *   GET monitor/disk     → actionDisk   (JSON)
 *   GET monitor/errors   → actionErrors (JSON)
 */
class MonitorController extends Controller
{
    /** Views live inside the module's own src/views directory */
    public function getViewPath(): string
    {
        return dirname(__DIR__, 2) . '/views';
    }

    public function behaviors(): array
    {
        return [
            'access' => [
                'class'         => AccessControl::class,
                'rules'         => [
                    [
                        'allow'         => true,
                        'matchCallback' => static function (): bool {
                            $user = Yii::$app->user->identity;
                            return $user !== null && method_exists($user, 'inGroup') && $user->inGroup('Global Admins');
                        },
                    ],
                ],
                'denyCallback'  => static function (): void {
                    $user = Yii::$app->user;

                    Yii::warning(
                        sprintf(
                            'Monitor web access denied — user: %s, IP: %s',
                            $user->isGuest ? 'guest' : (string) $user->id,
                            Yii::$app->request->userIP ?? 'unknown'
                        ),
                        'security'
                    );

                    if ($user->isGuest) {
                        Yii::$app->response->redirect(['/site/login']);
                        return;
                    }

                    throw new ForbiddenHttpException('Access restricted to Global Admins.');
                },
            ],
        ];
    }

    /** HTML dashboard (initial page load). */
    public function actionIndex(): string
    {
        $service = $this->makeService();
        $data    = $service->all();

        return $this->render('monitor/index', [
            'data'    => $data,
            'service' => $service,
        ]);
    }

    /** Full JSON snapshot — used by the dashboard auto-refresh. */
    public function actionAll(): Response
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return $this->asJson(
            $this->makeService()->all(
                (int) Yii::$app->request->get('error_minutes', 60)
            )
        );
    }

    public function actionHealth(): Response
    {
        $modules = $this->makeService()->modules();
        $allOk   = !in_array('unavailable', array_column($modules, 'status'), true);

        Yii::$app->response->format = Response::FORMAT_JSON;
        return $this->asJson([
            'timestamp' => date('c'),
            'status'    => $allOk ? 'healthy' : 'degraded',
            'modules'   => $modules,
        ]);
    }

    public function actionQueues(): Response
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return $this->asJson([
            'timestamp' => date('c'),
            'queues'    => $this->makeService()->queues(),
        ]);
    }

    public function actionDb(): Response
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return $this->asJson(
            array_merge(['timestamp' => date('c')], $this->makeService()->database())
        );
    }

    public function actionDisk(): Response
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return $this->asJson([
            'timestamp' => date('c'),
            'disk'      => $this->makeService()->disk(),
        ]);
    }

    public function actionErrors(): Response
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        return $this->asJson(
            array_merge(
                ['timestamp' => date('c')],
                $this->makeService()->errors(
                    (int) Yii::$app->request->get('error_minutes', 60)
                )
            )
        );
    }

    // -------------------------------------------------------------------------

    private function makeService(): MonitorService
    {
        $service = new MonitorService();

        $get = Yii::$app->request->get(...);

        if (($v = $get('warn_waiting'))      !== null) { $service->warnWaiting     = (int) $v; }
        if (($v = $get('warn_stalled'))      !== null) { $service->warnStalled     = (int) $v; }
        if (($v = $get('warn_age_seconds'))  !== null) { $service->warnAgeSeconds  = (int) $v; }
        if (($v = $get('warn_disk_percent')) !== null) { $service->warnDiskPercent = (int) $v; }

        return $service;
    }
}
