<?php

namespace App\Services\Security;

use App\Models\AgentSecurityFinding;
use App\Services\Ai\Router as AiRouter;

/**
 * Drafts a formal customer-suspension ticket from a confirmed security
 * finding. The output is never auto-sent — it's stored as a draft and
 * the operator must hit "Send" after reviewing.
 *
 * Template structure mirrors the example HostSeba sent for the original
 * Webuzo cryptojacking incident:
 *   - Subject (clear, severity-up-front)
 *   - Greeting
 *   - Account details (cPanel/Webuzo user, server, IP)
 *   - Reason (with citation to Bangladesh Bank circular Dec 2017
 *     prohibiting cryptocurrency mining under BD law)
 *   - Forensic evidence (PID, file path with SHA-256 hash,
 *     persistence mechanism, outbound destination)
 *   - Impact statement (shared-server resource abuse)
 *   - Legal & compliance notice
 *   - No-data-recovery clause
 *   - Closing
 *
 * We hand the AI the structured evidence + the template skeleton; it
 * fills in the prose. We never let the AI invent evidence — every
 * forensic claim in the draft must be backed by a field on the
 * AgentSecurityFinding row.
 */
class SuspensionTicketDrafter
{
    public function __construct(private AiRouter $ai) {}

    public function draft(AgentSecurityFinding $finding, ?string $operatorNotes = null): array
    {
        $finding->loadMissing('server', 'scan');
        $server   = $finding->server;
        $evidence = $finding->evidence ?? [];

        // Gather sibling findings on the same server+user from the same scan
        // — the original incident had cron + bashrc + binary + outbound
        // simultaneously, and the ticket needs all four sections.
        $sibling = collect();
        if ($finding->scan_id && $finding->unix_user) {
            $sibling = AgentSecurityFinding::where('scan_id', $finding->scan_id)
                ->where('unix_user', $finding->unix_user)
                ->where('id', '!=', $finding->id)
                ->get();
        }

        $system = <<<SYS
You draft formal customer-account suspension tickets for HostSeba, a
Bangladesh hosting company. The draft must be:

* Professional but firm — the account WILL be suspended; do not soften.
* Grounded ONLY in the forensic evidence provided in the user message.
  Do not invent process names, file paths, hashes, IPs, or timestamps.
* Reference Bangladesh Bank circular dated 2017-12-24 prohibiting
  cryptocurrency mining / trading under BD law — this is the legal
  basis for immediate suspension when mining is detected.
* Include a "no data recovery" clause: data on a suspended account
  pending abuse investigation is not restorable until the account
  is reinstated.
* End with HostSeba's standard staff signoff (do not invent a name —
  use "HostSeba Abuse Team").

Structure the draft as plain text with these labeled sections, in
this order:

Subject: [single line]

Dear <Customer / username>,

ACCOUNT DETAILS
SUSPENSION REASON
FORENSIC EVIDENCE
IMPACT ON SHARED INFRASTRUCTURE
LEGAL & COMPLIANCE NOTICE
DATA RECOVERY
NEXT STEPS

Sincerely,
HostSeba Abuse Team

Do not include markdown. No bullet symbols other than "-". No emoji.
Output ONLY the ticket text — no preamble, no explanation.
SYS;

        $userPayload = $this->buildEvidenceBlock($finding, $sibling, $server, $operatorNotes);

        $result = $this->ai->complete(
            $system,
            $userPayload,
            taskClass: 'reason_complex',
            purpose:   'security_suspension_draft',
            subject:   ['type' => 'agent_security_finding', 'id' => $finding->id],
        );

        return [
            'ok'        => $result['ok'] ?? false,
            'draft'     => $result['text'] ?? '',
            'error'     => $result['error'] ?? null,
            'provider'  => $result['provider'] ?? null,
            'model'     => $result['model'] ?? null,
            'tokens_in' => $result['tokens_in'] ?? 0,
            'tokens_out'=> $result['tokens_out'] ?? 0,
        ];
    }

    private function buildEvidenceBlock(
        AgentSecurityFinding $f,
        \Illuminate\Support\Collection $sibling,
        $server,
        ?string $operatorNotes,
    ): string {
        $hostname = $server->hostname ?? '(unknown)';
        $ip       = $server->ip       ?? '(unknown)';
        $user     = $f->unix_user     ?? '(unknown)';
        $detected = $f->detected_at?->toIso8601String() ?? '(unknown)';

        // Each finding becomes one bullet block. The AI rewrites these
        // into prose under the FORENSIC EVIDENCE section.
        $blocks = collect([$f])->merge($sibling)->map(function (AgentSecurityFinding $row) {
            $lines = [
                '- category: ' . $row->category,
                '- severity: ' . $row->severity,
            ];
            if ($row->file_path)         $lines[] = '- file: ' . $row->file_path;
            if ($row->file_hash_sha256)  $lines[] = '- sha256: ' . $row->file_hash_sha256;
            if ($row->file_size_bytes !== null)  $lines[] = '- size_bytes: ' . $row->file_size_bytes;
            if ($row->file_permissions)  $lines[] = '- permissions: ' . $row->file_permissions;
            if ($row->process_pid)       $lines[] = '- pid: ' . $row->process_pid;
            if ($row->process_name)      $lines[] = '- process_name: ' . $row->process_name;
            if ($row->process_cmdline)   $lines[] = '- cmdline: ' . $row->process_cmdline;
            if ($row->process_cpu_percent !== null) $lines[] = '- cpu_percent: ' . $row->process_cpu_percent;
            if ($row->remote_ip)         $lines[] = '- remote: ' . $row->remote_ip . ':' . $row->remote_port;
            if (is_array($row->evidence) && ! empty($row->evidence)) {
                $lines[] = '- evidence: ' . json_encode($row->evidence, JSON_UNESCAPED_SLASHES);
            }
            return implode("\n", $lines);
        })->implode("\n\n");

        $notes = $operatorNotes
            ? "\n\nOPERATOR NOTES (incorporate as appropriate, do not quote verbatim):\n" . trim($operatorNotes)
            : '';

        return <<<USR
Draft a suspension ticket for the customer account below.

ACCOUNT
- unix_user: {$user}
- server_hostname: {$hostname}
- server_ip: {$ip}
- first_detected_at: {$detected}

EVIDENCE (one block per finding):

{$blocks}
{$notes}

Write the ticket now. Output the ticket text only — no commentary.
USR;
    }
}
