<?php

namespace App\Services;

use App\Models\ChangeEvent;
use App\Models\Incident;
use App\Models\Server;
use Illuminate\Support\Collection;

/**
 * Root cause hint generator. Runs at incident-open time and snapshots
 * "what's been happening on this server lately?" — config changes, package
 * updates, deploys, recent crons that failed, new processes spawned.
 *
 * The output is stored on the incident as `root_cause_hints` (JSON) so the
 * triaging operator sees it immediately rather than having to dig through
 * several logs.
 *
 * Not AI — just structured correlation. Things that happened in the last
 * 60 minutes that COULD be related, presented in time order.
 */
class RootCauseAnalyzer
{
    /**
     * Generates hints for an incident. Returns an array of hint objects:
     *   [
     *     ['type' => 'change_event', 'time' => '2026-05-07 14:23:11',
     *      'summary' => 'cron edited for cpanel_user shopuser', 'severity' => 'low'],
     *     ['type' => 'related_incident', 'time' => '...',
     *      'summary' => 'mysql slow queries spike on db-01', 'severity' => 'medium'],
     *   ]
     */
    public function analyze(Incident $incident): array
    {
        $hints = [];

        if ($incident->subject_type === Server::class && $incident->subject_id) {
            $hints = array_merge(
                $hints,
                $this->changeEventsBefore($incident),
                $this->relatedIncidentsBefore($incident),
                $this->dependencyIssues($incident),
            );
        }

        // Sort by time descending — most recent first
        usort($hints, fn ($a, $b) => strtotime($b['time']) <=> strtotime($a['time']));

        return $hints;
    }

    /**
     * Updates the incident with hints. Should be called after creating an
     * incident, before sending notifications.
     */
    public function attachHints(Incident $incident): void
    {
        $hints = $this->analyze($incident);
        if (!empty($hints)) {
            $incident->update(['root_cause_hints' => $hints]);
        }
    }

    /**
     * Change events on the same server in the last 60 minutes.
     *
     * Schema notes: change_events uses `occurred_at`, `category`, `details` (json).
     * The agent stuffs the original `event_type`, `target`, and `severity` into
     * details so we can present them — but the canonical columns are different.
     */
    protected function changeEventsBefore(Incident $incident): array
    {
        $cutoff = $incident->created_at->copy()->subMinutes(60);

        $events = ChangeEvent::where('server_id', $incident->subject_id)
            ->where('occurred_at', '>=', $cutoff)
            ->where('occurred_at', '<=', $incident->created_at)
            ->orderBy('occurred_at', 'desc')
            ->limit(10)
            ->get();

        return $events->map(fn ($e) => [
            'type' => 'change_event',
            'time' => $e->occurred_at->toIso8601String(),
            'summary' => $e->summary,
            'severity' => $e->details['severity'] ?? 'low',
            'event_type' => $e->details['event_type'] ?? $e->category,
            'category' => $e->category,
        ])->all();
    }

    /**
     * Other open incidents on the same server, opened just before this one.
     * Useful for "Apache went down RIGHT after MySQL did" correlation.
     */
    protected function relatedIncidentsBefore(Incident $incident): array
    {
        $cutoff = $incident->created_at->copy()->subMinutes(15);

        $related = Incident::where('id', '!=', $incident->id)
            ->where('subject_type', Server::class)
            ->where('subject_id', $incident->subject_id)
            ->where('created_at', '>=', $cutoff)
            ->where('created_at', '<=', $incident->created_at)
            ->orderBy('created_at', 'desc')
            ->limit(5)
            ->get();

        return $related->map(fn ($r) => [
            'type' => 'related_incident',
            'time' => $r->created_at->toIso8601String(),
            'summary' => $r->title,
            'severity' => $r->severity,
            'incident_id' => $r->id,
        ])->all();
    }

    /**
     * If this server depends on others (via server_dependencies), check if
     * any dependency target has an active issue.
     */
    protected function dependencyIssues(Incident $incident): array
    {
        $deps = \App\Models\ServerDependency::where('source_server_id', $incident->subject_id)
            ->with('target')
            ->get();

        $hints = [];
        foreach ($deps as $dep) {
            $targetIncidents = Incident::where('subject_type', Server::class)
                ->where('subject_id', $dep->target_server_id)
                ->where('status', 'open')
                ->where('created_at', '>=', now()->subHour())
                ->orderBy('severity', 'desc')
                ->first();

            if ($targetIncidents && $dep->target) {
                $hints[] = [
                    'type' => 'dependency_issue',
                    'time' => $targetIncidents->created_at->toIso8601String(),
                    'summary' => "Dependency '{$dep->target->name}' has an active {$targetIncidents->severity} incident: {$targetIncidents->title}",
                    'severity' => $targetIncidents->severity,
                    'relationship' => $dep->relationship,
                    'incident_id' => $targetIncidents->id,
                ];
            }
        }

        return $hints;
    }
}
