<?php

declare(strict_types=1);

require_once __DIR__ . '/../../vendor/autoload.php';

use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheIdentifier;
use App\Framework\Cache\CacheKey;
use App\Framework\Cache\CacheItem;
use App\Framework\Cache\CacheResult;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\DateTime\SystemClock;
use App\Framework\ErrorAggregation\ErrorAggregator;
use App\Framework\ErrorAggregation\Storage\InMemoryErrorStorage;
use App\Framework\ErrorHandling\ErrorHandler;
use App\Framework\ErrorReporting\ErrorReporter;
use App\Framework\ErrorReporting\Storage\InMemoryErrorReportStorage;
use App\Framework\Exception\Core\DatabaseErrorCode;
use App\Framework\Exception\FrameworkException;
use App\Framework\Http\RequestIdGenerator;
use App\Framework\Http\ResponseEmitter;
use App\Framework\DI\DefaultContainer;
use App\Framework\Queue\InMemoryQueue;

// Create all dependencies
$container = new DefaultContainer();
$emitter = new ResponseEmitter();
$requestIdGenerator = new RequestIdGenerator();

// Error Aggregation setup
$errorStorage = new InMemoryErrorStorage();
$cache = new class implements Cache {
    private array $data = [];

    public function get(CacheIdentifier ...$identifiers): CacheResult
    {
        $items = [];
        foreach ($identifiers as $identifier) {
            $keyStr = $identifier->toString();
            if (isset($this->data[$keyStr])) {
                $items[] = $this->data[$identifier->toString()];
            } else {
                $items[] = CacheItem::miss($identifier instanceof CacheKey ? $identifier : CacheKey::fromString($identifier->toString()));
            }
        }

        return count($items) === 1
            ? CacheResult::single($items[0])
            : CacheResult::multiple($items);
    }

    public function set(CacheItem ...$items): bool
    {
        foreach ($items as $item) {
            $this->data[$item->key->toString()] = $item;
        }
        return true;
    }

    public function has(CacheIdentifier ...$identifiers): array
    {
        $result = [];
        foreach ($identifiers as $identifier) {
            $result[] = isset($this->data[$identifier->toString()]);
        }
        return $result;
    }

    public function forget(CacheIdentifier ...$identifiers): bool
    {
        foreach ($identifiers as $identifier) {
            unset($this->data[$identifier->toString()]);
        }
        return true;
    }

    public function clear(): bool
    {
        $this->data = [];
        return true;
    }

    public function remember(CacheKey $key, callable $callback, ?Duration $ttl = null): CacheItem
    {
        $keyStr = $key->toString();
        if (isset($this->data[$keyStr])) {
            return $this->data[$keyStr];
        }

        $value = $callback();
        $item = $ttl ? CacheItem::forSetting($key, $value, $ttl) : CacheItem::miss($key);
        $this->data[$keyStr] = $item;
        return $item;
    }
};
$clock = new SystemClock();
$alertQueue = new InMemoryQueue();

$errorAggregator = new ErrorAggregator(
    storage: $errorStorage,
    cache: $cache,
    clock: $clock,
    alertQueue: $alertQueue,
    logger: null,
    batchSize: 100,
    maxRetentionDays: 90
);

// Error Reporting setup
$errorReportStorage = new InMemoryErrorReportStorage();
$reportQueue = new InMemoryQueue();

$errorReporter = new ErrorReporter(
    storage: $errorReportStorage,
    clock: $clock,
    logger: null,
    queue: $reportQueue,
    asyncProcessing: false,
    processors: [],
    filters: []
);

// Create ErrorHandler
$errorHandler = new ErrorHandler(
    emitter: $emitter,
    container: $container,
    requestIdGenerator: $requestIdGenerator,
    errorAggregator: $errorAggregator,
    errorReporter: $errorReporter,
    logger: null,
    isDebugMode: true,
    securityHandler: null
);

echo "=== Testing Error Pipeline ===\n\n";

// Create test exception
$exception = FrameworkException::create(
    DatabaseErrorCode::QUERY_FAILED,
    'Test database error'
);

echo "1. Creating ErrorHandlerContext manually...\n";
$errorHandlerContext = (new \ReflectionClass($errorHandler))->getMethod('createErrorHandlerContext')->invoke($errorHandler, $exception, null);
echo "   Context created successfully\n";
echo "   ExceptionContext: operation={$errorHandlerContext->exception->operation}, component={$errorHandlerContext->exception->component}\n";

echo "\n2. Testing ErrorEvent::fromErrorHandlerContext...\n";
try {
    $errorEvent = \App\Framework\ErrorAggregation\ErrorEvent::fromErrorHandlerContext($errorHandlerContext, $clock);
    echo "   ErrorEvent created successfully\n";
    echo "   Event ID: {$errorEvent->id}\n";
    echo "   Event message: {$errorEvent->errorMessage}\n";
} catch (\Throwable $e) {
    echo "   EXCEPTION in fromErrorHandlerContext: " . $e->getMessage() . "\n";
    echo "   AT: " . $e->getFile() . ":" . $e->getLine() . "\n";
    echo "   TRACE:\n";
    foreach ($e->getTrace() as $frame) {
        $file = $frame['file'] ?? 'unknown';
        $line = $frame['line'] ?? 0;
        $function = $frame['function'] ?? 'unknown';
        echo "      $file:$line - $function()\n";
    }
    exit(1);
}

echo "\n3. Testing ErrorAggregator.processError directly...\n";
try {
    $errorAggregator->processError($errorHandlerContext);
    echo "   processError completed successfully\n";
} catch (\Throwable $e) {
    echo "   EXCEPTION in processError: " . $e->getMessage() . "\n";
    echo "   AT: " . $e->getFile() . ":" . $e->getLine() . "\n";
    throw $e;
}

echo "\n3. Creating HTTP response from exception...\n";
$response = $errorHandler->createHttpResponse($exception);

echo "\n4. Checking ErrorAggregator storage...\n";
$events = $errorStorage->getRecentEvents(10);
echo "   Events stored: " . count($events) . "\n";
if (count($events) > 0) {
    echo "   First event message: " . $events[0]->message . "\n";
    echo "   First event severity: " . $events[0]->severity->value . "\n";
} else {
    echo "   No events stored!\n";
}

echo "\n3. Checking ErrorReporter storage...\n";
$reports = $errorReportStorage->findRecent(10);
echo "   Reports stored: " . count($reports) . "\n";
if (count($reports) > 0) {
    echo "   First report message: " . $reports[0]->message . "\n";
    echo "   First report exception: " . $reports[0]->exception . "\n";
    echo "   First report level: " . $reports[0]->level . "\n";
} else {
    echo "   No reports stored!\n";
}

echo "\n=== Test Complete ===\n";
