<?php

declare(strict_types=1);

namespace App\Framework\Database\Indexing;

use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheKey;
use App\Framework\Cache\CacheItem;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Database\Indexing\ValueObjects\IndexName;
use App\Framework\Database\Indexing\ValueObjects\IndexUsageMetrics;
use DateTimeImmutable;

/**
 * Tracks real index usage statistics over time
 *
 * Stores usage data in cache for performance analysis
 */
final readonly class IndexUsageTracker
{
    private const CACHE_PREFIX = 'index_usage_';
    private const CACHE_TTL_DAYS = 30;

    public function __construct(
        private Cache $cache,
        private IndexAnalyzer $analyzer
    ) {}

    /**
     * Record index usage for a query
     */
    public function recordUsage(string $sql, string $tableName): void
    {
        $analysis = $this->analyzer->analyzeQuery($sql);

        foreach ($analysis['indexes_used'] as $indexName) {
            $this->incrementUsage(
                indexName: $indexName,
                tableName: $tableName,
                rowsExamined: $analysis['rows_examined'],
                rowsReturned: $this->estimateRowsReturned($analysis)
            );
        }
    }

    /**
     * Get usage metrics for a specific index
     */
    public function getUsageMetrics(IndexName $indexName, string $tableName): ?IndexUsageMetrics
    {
        $cacheKey = $this->getCacheKey($indexName, $tableName);
        $cached = $this->cache->get($cacheKey);

        if (!$cached) {
            return null;
        }

        $data = $cached->value;

        return new IndexUsageMetrics(
            indexName: $indexName,
            tableName: $tableName,
            usageCount: $data['usage_count'] ?? 0,
            scanCount: $data['scan_count'] ?? 0,
            selectivity: $this->calculateSelectivity($data),
            rowsExamined: $data['rows_examined'] ?? 0,
            rowsReturned: $data['rows_returned'] ?? 0,
            lastUsed: new DateTimeImmutable($data['last_used'] ?? 'now'),
            createdAt: new DateTimeImmutable($data['created_at'] ?? 'now')
        );
    }

    /**
     * Get usage metrics for all indexes on a table
     *
     * @return array<IndexUsageMetrics>
     */
    public function getTableUsageMetrics(string $tableName): array
    {
        $indexes = $this->analyzer->getTableIndexes($tableName);
        $metrics = [];

        foreach ($indexes as $index) {
            $indexName = new IndexName($index['name']);
            $usage = $this->getUsageMetrics($indexName, $tableName);

            if ($usage) {
                $metrics[] = $usage;
            }
        }

        return $metrics;
    }

    /**
     * Get usage statistics summary for all tracked indexes
     *
     * @return array{
     *     total_indexes: int,
     *     used_indexes: int,
     *     unused_indexes: int,
     *     average_usage: float,
     *     total_queries: int
     * }
     */
    public function getGlobalStatistics(): array
    {
        // This would require iterating all cached index metrics
        // For now, return basic structure
        return [
            'total_indexes' => 0,
            'used_indexes' => 0,
            'unused_indexes' => 0,
            'average_usage' => 0.0,
            'total_queries' => 0
        ];
    }

    /**
     * Reset usage statistics for an index
     */
    public function resetUsage(IndexName $indexName, string $tableName): void
    {
        $cacheKey = $this->getCacheKey($indexName, $tableName);
        $this->cache->forget($cacheKey);
    }

    /**
     * Reset all usage statistics
     */
    public function resetAll(): void
    {
        // This would require cache prefix-based deletion
        // Implementation depends on cache driver capabilities
    }

    /**
     * Increment usage count for an index
     */
    private function incrementUsage(
        IndexName $indexName,
        string $tableName,
        int $rowsExamined,
        int $rowsReturned
    ): void {
        $cacheKey = $this->getCacheKey($indexName, $tableName);
        $cached = $this->cache->get($cacheKey);

        $data = $cached ? $cached->value : $this->initializeUsageData();

        $data['usage_count']++;
        $data['scan_count']++;
        $data['rows_examined'] += $rowsExamined;
        $data['rows_returned'] += $rowsReturned;
        $data['last_used'] = (new DateTimeImmutable())->format('Y-m-d H:i:s');

        $cacheItem = CacheItem::forSetting(
            key: $cacheKey,
            value: $data,
            ttl: Duration::fromDays(self::CACHE_TTL_DAYS)
        );

        $this->cache->set($cacheItem);
    }

    /**
     * Initialize empty usage data structure
     */
    private function initializeUsageData(): array
    {
        $now = new DateTimeImmutable();

        return [
            'usage_count' => 0,
            'scan_count' => 0,
            'rows_examined' => 0,
            'rows_returned' => 0,
            'last_used' => $now->format('Y-m-d H:i:s'),
            'created_at' => $now->format('Y-m-d H:i:s')
        ];
    }

    /**
     * Calculate index selectivity (0.0 = all rows, 1.0 = unique rows)
     */
    private function calculateSelectivity(array $data): float
    {
        $rowsExamined = $data['rows_examined'] ?? 0;
        $rowsReturned = $data['rows_returned'] ?? 0;

        if ($rowsExamined === 0) {
            return 1.0;
        }

        return 1.0 - ($rowsReturned / $rowsExamined);
    }

    /**
     * Estimate rows returned from EXPLAIN analysis
     */
    private function estimateRowsReturned(array $analysis): int
    {
        // For now, assume 10% of examined rows are returned
        // This is a rough estimate; actual tracking would need query result counting
        return (int) ($analysis['rows_examined'] * 0.1);
    }

    /**
     * Generate cache key for index usage data
     */
    private function getCacheKey(IndexName $indexName, string $tableName): CacheKey
    {
        return CacheKey::fromString(
            self::CACHE_PREFIX . "{$tableName}_{$indexName->toString()}"
        );
    }
}
