<?php

namespace App\Livewire\Modals;

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

/**
 * Add a firewall rule. For ufw the operator picks action/protocol/port/source; for
 * firewalld (an allow-list default zone) it opens a port. All validation happens in
 * FirewallService — this modal only collects and forwards. Adding is non-destructive,
 * so no R5 confirm (deleting a rule is the guarded path).
 */
class FirewallRule extends ModalComponent
{
    public int $serverId;

    public string $tool = 'ufw';

    public string $action = 'allow';

    public string $proto = 'tcp';

    public string $port = '';

    public string $from = '';

    public ?string $error = null;

    public function mount(int $serverId, string $tool = 'ufw'): void
    {
        abort_unless(auth()->user()?->can('manage-network'), 403);

        $this->serverId = $serverId;
        $this->tool = $tool === 'firewalld' ? 'firewalld' : 'ufw';
    }

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

    public function save(FirewallService $firewall): 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;
        }

        $port = trim($this->port) !== '' ? (int) $this->port : null;

        try {
            $res = $firewall->addRule($server, $this->action, $this->proto, $port, $this->from);
        } catch (Throwable $e) {
            $this->error = $e->getMessage();

            return;
        }

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

            return;
        }

        AuditEvent::create([
            'user_id' => Auth::id(),
            'server_id' => $server->id,
            'actor' => Auth::user()?->name ?? 'system',
            'action' => 'firewall.rule_add',
            'target' => $server->name.' · '.$this->summary($port),
            'ip' => request()->ip(),
        ]);

        $this->dispatch('firewallChanged');
        $this->dispatch('notify', message: __('modals.firewall_rule.notify_added'));
        $this->closeModal();
    }

    /** Short human summary of the rule for the audit log. */
    private function summary(?int $port): string
    {
        if ($this->tool === 'firewalld') {
            return __('modals.firewall_rule.summary_port_opened', [
                'port' => (string) $port,
                'proto' => $this->proto === 'udp' ? 'udp' : 'tcp',
            ]);
        }

        $parts = [$this->action];
        if ($port !== null) {
            $parts[] = $port.($this->proto !== 'any' ? '/'.$this->proto : '');
        }
        if (trim($this->from) !== '') {
            $parts[] = __('modals.firewall_rule.summary_from', ['source' => trim($this->from)]);
        }

        return implode(' ', $parts);
    }

    public function render()
    {
        return view('livewire.modals.firewall-rule');
    }
}
