<?php

declare(strict_types=1);

namespace App\Filament\Jabali\Pages;

use App\Models\AuditLog;
use App\Services\Agent\AgentClient;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Url;

class Logs extends Page implements HasActions, HasForms
{
    use InteractsWithActions;
    use InteractsWithForms;

    protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-document-text';

    public static function getNavigationLabel(): string
    {
        return __('Logs & Statistics');
    }

    protected static ?int $navigationSort = 13;

    protected static ?string $slug = 'logs';

    protected string $view = 'filament.jabali.pages.logs';

    protected ?AgentClient $agent = null;

    #[Url]
    public ?string $selectedDomain = null;

    #[Url(as: 'tab')]
    public string $activeTab = 'logs';

    public string $logType = 'access';

    public int $logLines = 100;

    public string $logContent = '';

    public array $logInfo = [];

    public bool $statsGenerated = false;

    public string $statsUrl = '';

    public array $domains = [];

    public function getTitle(): string|Htmlable
    {
        return __('Logs & Statistics');
    }

    public function mount(): void
    {
        $this->loadDomains();
        $this->activeTab = $this->normalizeTab($this->activeTab);

        if (! empty($this->domains) && ! $this->selectedDomain) {
            $this->selectedDomain = $this->domains[0]['domain'] ?? null;
        }

        if ($this->selectedDomain) {
            $this->loadLogs();
        }
    }

    public function updatedActiveTab(): void
    {
        $this->activeTab = $this->normalizeTab($this->activeTab);
        if ($this->activeTab === 'logs' && $this->selectedDomain) {
            $this->loadLogs();
        }
    }

    public function setTab(string $tab): void
    {
        $this->activeTab = $this->normalizeTab($tab);
    }

    protected function normalizeTab(?string $tab): string
    {
        return match ($tab) {
            'logs', 'activity', 'stats' => (string) $tab,
            default => 'logs',
        };
    }

    protected function getAgent(): AgentClient
    {
        if ($this->agent === null) {
            $this->agent = new AgentClient;
        }

        return $this->agent;
    }

    protected function getUsername(): string
    {
        return Auth::user()->username ?? Auth::user()->name ?? 'unknown';
    }

    protected function loadDomains(): void
    {
        try {
            $result = $this->getAgent()->send('domain.list', [
                'username' => $this->getUsername(),
            ]);

            $this->domains = ($result['success'] ?? false) ? ($result['domains'] ?? []) : [];
        } catch (\Throwable $exception) {
            $this->domains = [];
        }
    }

    public function getDomainOptions(): array
    {
        $options = [];
        foreach ($this->domains as $domain) {
            $d = $domain['domain'] ?? $domain;
            $options[$d] = $d;
        }

        return $options;
    }

    public function updatedSelectedDomain(): void
    {
        $this->statsGenerated = false;
        $this->statsUrl = '';
        $this->loadLogs();
    }

    public function setLogType(string $type): void
    {
        $this->logType = $type;
        $this->loadLogs();
    }

    public function loadLogs(): void
    {
        if (! $this->selectedDomain) {
            $this->logContent = '';
            $this->logInfo = [];

            return;
        }

        try {
            $result = $this->getAgent()->send('logs.tail', [
                'username' => $this->getUsername(),
                'domain' => $this->selectedDomain,
                'type' => $this->logType,
                'lines' => $this->logLines,
            ]);

            if ($result['success'] ?? false) {
                $this->logContent = $result['content'] ?? '';
                $this->logInfo = [
                    'file_size' => $this->formatBytes($result['file_size'] ?? 0),
                    'last_modified' => $result['last_modified'] ?? '',
                    'lines' => $result['lines'] ?? 0,
                ];
            } else {
                $this->logContent = '';
                $this->logInfo = [];
            }
        } catch (\Exception $e) {
            $this->logContent = '';
            $this->logInfo = [];
        }
    }

    public function refreshLogs(): void
    {
        $this->loadLogs();
        Notification::make()
            ->title(__('Logs refreshed'))
            ->success()
            ->send();
    }

    public function getActivityLogs()
    {
        return AuditLog::query()
            ->where('user_id', Auth::id())
            ->latest()
            ->limit(50)
            ->get();
    }

    public function generateStats(): void
    {
        if (! $this->selectedDomain) {
            Notification::make()
                ->title(__('No domain selected'))
                ->danger()
                ->send();

            return;
        }

        try {
            $result = $this->getAgent()->send('logs.goaccess', [
                'username' => $this->getUsername(),
                'domain' => $this->selectedDomain,
                'period' => 'all',
            ]);

            if ($result['success'] ?? false) {
                $this->statsGenerated = true;
                $this->statsUrl = 'https://'.$this->selectedDomain.($result['report_url'] ?? '/stats/report.html');

                Notification::make()
                    ->title(__('Statistics generated'))
                    ->body(__('Report generated with :lines log entries', ['lines' => number_format($result['log_lines'] ?? 0)]))
                    ->success()
                    ->send();
            } else {
                Notification::make()
                    ->title(__('Error generating statistics'))
                    ->body($result['error'] ?? 'Unknown error')
                    ->danger()
                    ->send();
            }
        } catch (\Exception $e) {
            Notification::make()
                ->title(__('Error'))
                ->body($e->getMessage())
                ->danger()
                ->send();
        }
    }

    protected function getHeaderActions(): array
    {
        return [

            Action::make('generateStats')
                ->label(__('Generate Statistics'))
                ->icon('heroicon-o-chart-bar')
                ->color('primary')
                ->visible(fn () => $this->selectedDomain !== null && $this->activeTab === 'stats')
                ->action(fn () => $this->generateStats()),

            Action::make('refreshLogs')
                ->label(__('Refresh'))
                ->icon('heroicon-o-arrow-path')
                ->color('gray')
                ->visible(fn () => $this->selectedDomain !== null && $this->activeTab === 'logs')
                ->action(fn () => $this->refreshLogs()),
        ];
    }

    protected function formatBytes(int $bytes, int $precision = 2): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        $bytes /= pow(1024, $pow);

        return round($bytes, $precision).' '.$units[$pow];
    }
}
