<?php

declare(strict_types=1);

namespace App\Filament\Pages;

use App\Models\User;
use BackedEnum;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\URL;
use Throwable;
use UnitEnum;

class GenerateSitemap extends Page
{
    protected static ?string $title = '建立 SEO 檔案';

    protected static ?string $navigationLabel = '建立 SEO 檔案';

    protected static string|UnitEnum|null $navigationGroup = '系統管理';

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

    protected static ?int $navigationSort = 50;

    protected static ?string $slug = 'generate-sitemap';

    protected string $view = 'filament.pages.generate-sitemap';

    public ?string $sitemapUrl = null;

    public ?string $lastModifiedHuman = null;

    public ?string $robotsUrl = null;

    public ?string $robotsLastModifiedHuman = null;

    public static function canAccess(): bool
    {
        $user = Auth::user();

        return $user instanceof User
            && $user->hasAnyRole(['super_admin', 'admin']);
    }

    public function mount(): void
    {
        $this->refreshSeoMeta();
    }

    public function generate(): void
    {
        try {
            $exitCode = Artisan::call('seo:generate');
            $output = trim((string) Artisan::output());

            if ($exitCode !== 0) {
                throw new \RuntimeException($output !== '' ? $output : 'seo:generate failed');
            }

            $this->refreshSeoMeta();

            Notification::make()
                ->title('SEO 檔案已建立/更新')
                ->body($output !== '' ? $output : '已更新 sitemap.xml 與 robots.txt')
                ->success()
                ->send();
        } catch (Throwable $e) {
            report($e);

            Notification::make()
                ->title('建立 Sitemap 失敗')
                ->body($e->getMessage())
                ->danger()
                ->send();
        }
    }

    private function refreshSeoMeta(): void
    {
        $baseUrl = rtrim((string) env('SEO_BASE_URL', ''), '/');
        if ($baseUrl === '') {
            $baseUrl = rtrim((string) env('APP_URL', ''), '/');
        }
        if ($baseUrl === '') {
            $baseUrl = rtrim((string) config('app.url'), '/');
        }

        $sitemapRelativePath = 'sitemap.xml';
        $outputDir = rtrim((string) env('SEO_PUBLIC_PATH', ''), '/');
        $normalizedOutputDir = str_replace('\\', '/', $outputDir);
        $isAbsolute = $normalizedOutputDir !== ''
            && (
                str_starts_with($normalizedOutputDir, '/')
                || (bool) preg_match('/^[A-Za-z]:\//', $normalizedOutputDir)
                || str_starts_with($normalizedOutputDir, '//')
            );

        if ($outputDir !== '' && ! $isAbsolute) {
            $outputDir = rtrim((string) base_path($outputDir), '/');
        }
        $effectivePublicDir = $outputDir !== '' ? $outputDir : public_path();
        $sitemapFullPath = rtrim((string) $effectivePublicDir, '/\\') . DIRECTORY_SEPARATOR . $sitemapRelativePath;

        $this->sitemapUrl = $baseUrl !== ''
            ? ($baseUrl . '/' . $sitemapRelativePath)
            : URL::to('/' . $sitemapRelativePath);

        if (is_file($sitemapFullPath)) {
            $mtime = filemtime($sitemapFullPath);
            $this->lastModifiedHuman = $mtime ? date('Y-m-d H:i:s', $mtime) : null;
        } else {
            $this->lastModifiedHuman = null;
        }

        $robotsRelativePath = 'robots.txt';
        $robotsFullPath = rtrim((string) $effectivePublicDir, '/\\') . DIRECTORY_SEPARATOR . $robotsRelativePath;

        $this->robotsUrl = $baseUrl !== ''
            ? ($baseUrl . '/' . $robotsRelativePath)
            : URL::to('/' . $robotsRelativePath);

        if (is_file($robotsFullPath)) {
            $mtime = filemtime($robotsFullPath);
            $this->robotsLastModifiedHuman = $mtime ? date('Y-m-d H:i:s', $mtime) : null;
        } else {
            $this->robotsLastModifiedHuman = null;
        }
    }
}
