<?php

declare(strict_types=1);

use App\Http\Middleware\DemoMode;
use App\Http\Middleware\EnforceTwoFactor;
use App\Http\Middleware\IdentifyTenant;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
        apiPrefix: 'api',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        // W·Dot v1.0: API rate limit + tenant identification on every /api/* request.
        // throttle:api 는 config/wdot.php throttle.api 에서 정의됨 (60/min by default).
        //
        // DemoMode is PREPENDED so it runs before IdentifyTenant and binds the
        // per-IP sandbox tenant. When DEMO_MODE_ENABLED=false (production) the
        // middleware is a fast no-op.
        $middleware->api(prepend: [
            DemoMode::class,
        ]);

        $middleware->api(append: [
            'throttle:api',
            IdentifyTenant::class,
        ]);

        // W·Dot Installer: /install/* is guarded by InstallerOnly middleware
        // (returns 403 once install.lock exists) + throttle:installer (10/min/IP).
        // Session-based CSRF is unnecessary because the install SPA's index.html
        // is served statically (no <meta csrf-token>), and is a one-time setup flow.
        $middleware->validateCsrfTokens(except: [
            'install/*',
        ]);

        $middleware->alias([
            'tenant' => IdentifyTenant::class,
            'demo' => DemoMode::class,
            'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
            'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
            '2fa.enforce' => EnforceTwoFactor::class,
        ]);
    })
    ->withSchedule(function (Schedule $schedule): void {
        // Telescope 7일 보관
        $schedule->command('telescope:prune --hours=168')->dailyAt('03:00');

        // 백업 (DB + Files + Code, 매일 03:30)
        $schedule->command('backup:run --type=all --rotate=14')->dailyAt('03:30');

        // 컴플라이언스 자가 점검 (매일 04:00)
        $schedule->command('compliance:isms-check --silent')->dailyAt('04:00');

        // PIA 보고서 (매주 일요일 05:00)
        $schedule->command('compliance:pia-report --silent')->weeklyOn(0, '05:00');

        // Soft delete 90일 후 hard delete (매월 1일 02:00)
        $schedule->command('compliance:purge --grace-days=90')->monthlyOn(1, '02:00');

        // Horizon snapshot (매 5분) — Horizon 설치 시에만 실행
        if (class_exists(\Laravel\Horizon\Console\SnapshotCommand::class)) {
            $schedule->command('horizon:snapshot')->everyFiveMinutes();
        }

        // Health check + 자동 알림 (매 5분)
        $schedule->call(function (): void {
            try {
                $response = \Illuminate\Support\Facades\Http::timeout(5)
                    ->get(config('app.url').'/api/v1/health');
                if (! $response->successful()) {
                    \Illuminate\Support\Facades\Log::error('Health check failed', [
                        'status' => $response->status(),
                    ]);
                }
            } catch (\Throwable $e) {
                \Illuminate\Support\Facades\Log::error('Health check exception', [
                    'message' => $e->getMessage(),
                ]);
            }
        })->everyFiveMinutes()->name('health-ping')->withoutOverlapping();

        // model:prune (Sun 02:00) — Telescope/Audit 오래된 행
        $schedule->command('model:prune')->weeklyOn(0, '02:00');

        // Demo sandbox cleanup (hourly) — removes expired per-IP sandboxes
        // and their orphaned tenant + admin user rows. No-op when demo
        // mode is disabled and no sandbox rows exist.
        $schedule->call(function (): void {
            try {
                if (\Illuminate\Support\Facades\Schema::hasTable('demo_sandboxes')) {
                    $removed = app(\App\Services\Demo\SandboxManager::class)->cleanup();
                    if ($removed > 0) {
                        \Illuminate\Support\Facades\Log::info('demo: cleanup removed sandboxes', [
                            'count' => $removed,
                        ]);
                    }
                }
            } catch (\Throwable $e) {
                \Illuminate\Support\Facades\Log::warning('demo: cleanup error', [
                    'message' => $e->getMessage(),
                ]);
            }
        })->hourly()->name('demo-cleanup')->withoutOverlapping();
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        // API 요청에서 인증 실패 → 401 JSON (H-3 / API-03)
        $exceptions->render(function (\Illuminate\Auth\AuthenticationException $e, $request) {
            if ($request->expectsJson() || $request->is('api/*')) {
                return response()->json([
                    'error' => 'UNAUTHENTICATED',
                    'message' => $e->getMessage(),
                ], 401);
            }
            return null;
        });
    })
    ->withProviders([
        App\Providers\AppServiceProvider::class,
        App\Providers\TenancyServiceProvider::class,
        App\Providers\InstallerServiceProvider::class,
    ])
    ->create();
