<?php

namespace App\Services;

use App\Models\Incident;
use App\Models\Server;
use App\Models\ServerDependency;
use App\Models\SuppressionWindow;
use Illuminate\Support\Facades\Log;

/**
 * Smart-mute & cascade suppression.
 *
 * Two suppression sources:
 *
 *   1) SuppressionWindow rows — operator-scheduled maintenance. The model
 *      already has a covers() method that knows how to evaluate scope (a
 *      JSON blob with optional servers[], tags[], detectors[]). We just
 *      iterate active windows and ask each one whether it covers this
 *      incident.
 *
 *   2) Dependency cascade — when a server this server depends on has an
 *      active medium+ incident from the last 30 min, we mark this incident
 *      as a child and suppress its notifications. The root incident still
 *      alerts; downstream noise is folded under it.
 *
 * Suppressed alerts are still recorded in the DB for audit — only the
 * notification dispatch is skipped.
 */
class SuppressionService
{
    /**
     * Should this incident's notifications be suppressed?
     */
    public function shouldSuppress(Incident $incident): bool
    {
        // Resolve numeric subject_id only if the incident's subject is a Server
        $serverId = ($incident->subject_type === Server::class) ? $incident->subject_id : null;
        $detector = $incident->detector;

        // 1) Maintenance windows
        $windows = SuppressionWindow::where('starts_at', '<=', now())
            ->where('ends_at', '>=', now())
            ->get();

        foreach ($windows as $w) {
            if ($w->covers($serverId, $detector, $incident->severity)) {
                Log::info("Incident #{$incident->id} suppressed by window '{$w->name}' (#{$w->id})");
                return true;
            }
        }

        // 2) Dependency cascade
        if ($serverId) {
            $deps = ServerDependency::where('source_server_id', $serverId)->get();
            foreach ($deps as $dep) {
                $rootIncident = Incident::where('subject_type', Server::class)
                    ->where('subject_id', $dep->target_server_id)
                    ->where('status', 'open')
                    ->where('created_at', '>=', now()->subMinutes(30))
                    ->where('severity', '!=', 'low')
                    ->first();

                if ($rootIncident) {
                    if (!$incident->parent_incident_id) {
                        $incident->update(['parent_incident_id' => $rootIncident->id]);
                    }
                    Log::info("Incident #{$incident->id} suppressed — child of root #{$rootIncident->id}");
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Convenience constructor for an ad-hoc maintenance window. The model
     * stores scope as JSON; we accept structured args and serialize them.
     *
     * @param array $args  reason, starts_at, ends_at, server_ids[],
     *                     detectors[], allow_critical, name
     */
    public function openWindow(array $args): SuppressionWindow
    {
        $scope = [];
        if (!empty($args['server_ids'])) $scope['servers'] = $args['server_ids'];
        if (!empty($args['detectors']))  $scope['detectors'] = $args['detectors'];
        if (!empty($args['tags']))       $scope['tags'] = $args['tags'];

        return SuppressionWindow::create([
            'name' => $args['name'] ?? 'Maintenance window',
            'reason' => $args['reason'] ?? null,
            'starts_at' => $args['starts_at'],
            'ends_at' => $args['ends_at'],
            'scope' => $scope,
            'digest_alerts' => $args['digest_alerts'] ?? true,
            'allow_critical' => $args['allow_critical'] ?? true,
            'created_by' => $args['created_by'] ?? null,
        ]);
    }
}
