<?php

declare(strict_types=1);

namespace App\Application\Debug;

use App\Framework\Attributes\Route;
use App\Framework\Config\Environment;
use App\Framework\Config\EnvKey;
use App\Framework\Http\Method;
use App\Framework\Http\Request;
use App\Framework\Router\Result\JsonResult;
use App\Framework\Router\Result\ViewResult;

/**
 * Interactive Debug Console Controller
 *
 * Provides a web-based REPL interface for debugging and development.
 * Only available in development mode for security.
 */
final readonly class DebugConsoleController
{
    public function __construct(
        private Environment $environment,
        private DebugCodeEvaluator $evaluator,
        private DebugHistoryManager $historyManager
    ) {
    }

    /**
     * Show the debug console UI
     */
    #[Route(path: '/debug/console', method: Method::GET)]
    public function console(Request $request): ViewResult
    {
        $this->ensureDevelopmentMode();

        return new ViewResult(
            template: 'debug/console',
            data: [
                'history' => $this->historyManager->getHistory(limit: 50),
                'context' => $this->getContextInfo($request),
            ]
        );
    }

    /**
     * Execute PHP code via AJAX
     */
    #[Route(path: '/debug/console/execute', method: Method::POST)]
    public function execute(Request $request): JsonResult
    {
        $this->ensureDevelopmentMode();

        $code = $request->parsedBody['code'] ?? '';

        if (empty($code)) {
            return new JsonResult([
                'success' => false,
                'error' => 'No code provided',
            ], 400);
        }

        try {
            $result = $this->evaluator->evaluate($code);

            // Save to history
            $this->historyManager->addEntry($code, $result);

            return new JsonResult([
                'success' => true,
                'result' => $result->output,
                'type' => $result->type,
                'executionTime' => $result->executionTime,
            ]);
        } catch (\Throwable $e) {
            return new JsonResult([
                'success' => false,
                'error' => $e->getMessage(),
                'trace' => $this->formatTrace($e),
            ], 500);
        }
    }

    /**
     * Get command history
     */
    #[Route(path: '/debug/console/history', method: Method::GET)]
    public function history(Request $request): JsonResult
    {
        $this->ensureDevelopmentMode();

        $limit = (int) ($request->query->get('limit') ?? 50);

        return new JsonResult([
            'history' => $this->historyManager->getHistory($limit),
        ]);
    }

    /**
     * Clear command history
     */
    #[Route(path: '/debug/console/history/clear', method: Method::POST)]
    public function clearHistory(Request $request): JsonResult
    {
        $this->ensureDevelopmentMode();

        $this->historyManager->clearHistory();

        return new JsonResult([
            'success' => true,
            'message' => 'History cleared successfully',
        ]);
    }

    private function ensureDevelopmentMode(): void
    {
        if (! $this->environment->getBool(EnvKey::APP_DEBUG, false)) {
            throw new \RuntimeException('Debug Console is only available in development mode');
        }
    }

    private function getContextInfo(Request $request): array
    {
        return [
            'php_version' => PHP_VERSION,
            'framework_version' => '1.0.0', // TODO: Get from config
            'memory_usage' => memory_get_usage(true),
            'memory_peak' => memory_get_peak_usage(true),
            'loaded_extensions' => get_loaded_extensions(),
        ];
    }

    private function formatTrace(\Throwable $e): array
    {
        return array_map(function ($trace) {
            return [
                'file' => $trace['file'] ?? 'unknown',
                'line' => $trace['line'] ?? 0,
                'function' => $trace['function'] ?? 'unknown',
                'class' => $trace['class'] ?? null,
            ];
        }, array_slice($e->getTrace(), 0, 10)); // Limit to 10 frames
    }
}
