<?php

/**
 * ============================================================
 * @project   biiproject
 * @author    Andika Debi Putra
 * @email     andikadebiputra@gmail.com
 * @website   https://biiproject.com
 * @copyright Copyright (c) 2026 Andika Debi Putra
 * @license   Proprietary - All Rights Reserved
 * @version   1.0.0
 * @created   2026-05-01
 * ============================================================
 */

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Spatie\Permission\Middleware\RoleMiddleware;
use Spatie\Permission\Middleware\PermissionMiddleware;
use Spatie\Permission\Middleware\RoleOrPermissionMiddleware;
use App\Http\Middleware\CheckActivePermission;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        channels: __DIR__.'/../routes/channels.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        // GLOBAL MIDDLEWARE
        $middleware->append(\App\Http\Middleware\GzipCompression::class);

        // REGISTER ALIAS MIDDLEWARE
        $middleware->alias([
            'role' => RoleMiddleware::class,
            'permission' => PermissionMiddleware::class,
            'role_or_permission' => RoleOrPermissionMiddleware::class,

            // CUSTOM MIDDLEWARE (CEK PERMISSION AKTIF)
            'active-permission' => CheckActivePermission::class,
            'password-expiry' => \App\Http\Middleware\PasswordExpiryMiddleware::class,
            'check-legal' => \App\Http\Middleware\CheckLegalAgreement::class,
            'mobile-guard' => \App\Http\Middleware\MobileMaintenanceMiddleware::class,
            'tab-permission' => \App\Http\Middleware\CheckTabPermission::class,
            'menu-permission' => \App\Http\Middleware\CheckMenuPermission::class,
        ]);

        $middleware->web(append: [
            \App\Http\Middleware\SecurityHeaders::class,
            \App\Http\Middleware\IpAccessControl::class,
            'password-expiry',
            'check-legal',
        ]);

    })
    ->withSchedule(function (\Illuminate\Console\Scheduling\Schedule $schedule): void {
        // Dikelola di routes/console.php
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        $exceptions->report(function (\Throwable $e) {
            // --- AI SELF HEALING INTERCEPTOR ---
            if (!($e instanceof \Symfony\Component\HttpKernel\Exception\HttpException)) {
                try {
                    // Re-entrancy guard: if the AI healer itself is currently running,
                    // never re-enter (prevents infinite loops if healing trips an error).
                    if (defined('AI_HEALER_RUNNING')) {
                        return;
                    }

                    $isAiHealingEnabled = false;
                    $isAiProviderEnabled = false;
                    try {
                        $isAiHealingEnabled = app(\App\Services\SystemConfig\SystemConfigService::class)
                            ->get('ai_healing_enabled', false);
                        $isAiProviderEnabled = app(\App\Services\SystemConfig\SystemConfigService::class)
                            ->get('ai_enabled', false);
                    } catch (\Throwable $t) {}

                    if (!$isAiHealingEnabled || !$isAiProviderEnabled) {
                        // Healer or Provider disabled — fall through to Sentry below.
                    } else {
                        // Skip exceptions originating *from* the healing pipeline itself
                        // OR from critical files we never want the healer to touch.
                        $traceStr = $e->getFile() . $e->getTraceAsString();
                        $msg      = (string) $e->getMessage();
                        $isInternalHealerError = str_contains($traceStr, 'AiHealerJob')
                            || str_contains($traceStr, 'AiHealingLog')
                            || str_contains($traceStr, 'AiSelfHealingController')
                            || str_contains($traceStr, 'app/Services/AI/')
                            // Self-exclusion: never let the healer try to edit these files.
                            || str_contains($msg, 'ai-self-healing.blade.php')
                            || str_contains($msg, 'navigation.blade.php')
                            || str_contains($msg, 'layouts/app.blade.php')
                            || str_contains($traceStr, 'ai-self-healing.blade.php')
                            || str_contains($traceStr, 'navigation.blade.php');

                        if (!$isInternalHealerError) {
                            // Dedup: same error_type already pending OR diagnosing.
                            // Diagnosing logs older than 5 min are considered stuck and reset to pending.
                            \App\Models\AiHealingLog::where('error_type', get_class($e))
                                ->where('status', 'diagnosing')
                                ->where('updated_at', '<', now()->subMinutes(5))
                                ->update(['status' => 'pending', 'action_taken' => 'Auto-reset from stuck diagnosing state']);

                            $duplicate = \App\Models\AiHealingLog::where('error_type', get_class($e))
                                ->whereIn('status', ['pending', 'diagnosing'])
                                ->where('created_at', '>=', now()->subMinutes(2))
                                ->exists();

                            if (!$duplicate) {
                                // --- CIRCUIT BREAKER ---
                                $maxPerHour = (int) app(\App\Services\SystemConfig\SystemConfigService::class)
                                    ->get('ai_healing_max_attempts_per_hour', 5);
                                
                                $recentCount = \App\Models\AiHealingLog::where('created_at', '>', now()->subHour())
                                    ->whereIn('status', ['resolved', 'pending', 'diagnosing'])
                                    ->count();

                                if ($recentCount >= $maxPerHour) {
                                    // Circuit breaker tripped! Only log to standard Laravel log, don't trigger AI.
                                    \Illuminate\Support\Facades\Log::warning("AI Healer Circuit Breaker tripped. Total fixes in last hour: {$recentCount}. Threshold: {$maxPerHour}");
                                    return;
                                }

                                define('AI_HEALER_RUNNING', true);

                                $log = \App\Models\AiHealingLog::create([
                                    'error_type'    => get_class($e),
                                    'error_message' => $e->getMessage(),
                                    'stack_trace'   => $e->getTraceAsString(),
                                    'status'        => 'pending',
                                ]);

                                try {
                                    \App\Jobs\AiHealerJob::dispatchSync(
                                        $log->id,
                                        $e->getFile(),
                                        $e->getLine()
                                    );
                                } catch (\Throwable $inner) {
                                    $log->update([
                                        'status'       => 'failed',
                                        'ai_diagnosis' => 'Healer dispatch crashed: ' . $inner->getMessage(),
                                        'action_taken' => 'Pipeline error',
                                    ]);
                                }
                            }
                        }
                    }
                } catch (\Throwable $err) {
                    // Silently ignore — never let the interceptor break error reporting.
                }
            }

            if (app()->bound('sentry') && app()->environment('production', 'staging')) {
                app('sentry')->captureException($e);
            }
        });
    })
    ->create();