<?php

namespace App\Livewire\Modals;

use App\Models\AuditEvent;
use App\Models\Server;
use App\Services\Fail2banService;
use Illuminate\Support\Facades\Auth;
use LivewireUI\Modal\ModalComponent;
use Throwable;

/**
 * Manually ban an IP in a fail2ban jail (R5: a deliberate confirm dialog, not a
 * native popup). Fail2banService refuses to ban loopback or Clusev's own connection,
 * so this can never lock the operator out.
 */
class Fail2banBan extends ModalComponent
{
    public int $serverId;

    /** @var array<int, string> */
    public array $jails = [];

    public string $jail = '';

    public string $ip = '';

    public ?string $error = null;

    /**
     * @param  array<int, string>  $jails
     */
    public function mount(int $serverId, array $jails = []): void
    {
        abort_unless(auth()->user()?->can('manage-network'), 403);

        $this->serverId = $serverId;
        $this->jails = array_values($jails);
        $this->jail = $this->jails[0] ?? 'sshd';
    }

    public static function modalMaxWidth(): string
    {
        return 'lg';
    }

    public function save(Fail2banService $fail2ban): void
    {
        abort_unless(auth()->user()?->can('manage-network'), 403);

        $this->error = null;

        $server = Server::find($this->serverId);
        if (! $server) {
            $this->error = __('common.server_not_found');

            return;
        }

        try {
            $res = $fail2ban->ban($server, $this->jail, trim($this->ip));
        } catch (Throwable $e) {
            $this->error = $e->getMessage();

            return;
        }

        if (! $res['ok']) {
            $this->error = $res['output'] !== '' ? $res['output'] : __('modals.fail2ban_ban.error_ban_failed');

            return;
        }

        AuditEvent::create([
            'user_id' => Auth::id(),
            'server_id' => $server->id,
            'actor' => Auth::user()?->name ?? 'system',
            'action' => 'fail2ban.ban',
            'target' => trim($this->ip).' · '.$this->jail.' · '.$server->name,
            'ip' => request()->ip(),
        ]);

        $this->dispatch('fail2banChanged');
        $this->dispatch('notify', message: __('modals.fail2ban_ban.notify_banned', ['ip' => trim($this->ip)]));
        $this->closeModal();
    }

    public function render()
    {
        return view('livewire.modals.fail2ban-ban');
    }
}
