<?php

declare(strict_types=1);

namespace App\Framework\Database\Indexing;

use App\Framework\Database\Indexing\ValueObjects\IndexRecommendation;

/**
 * Facade service for complete index optimization workflow
 *
 * Combines all index analysis components into unified interface
 */
final readonly class IndexOptimizationService
{
    public function __construct(
        private IndexAnalyzer $analyzer,
        private IndexUsageTracker $usageTracker,
        private UnusedIndexDetector $unusedDetector,
        private CompositeIndexGenerator $compositeGenerator,
        private IndexMigrationGenerator $migrationGenerator
    ) {}

    /**
     * Generate complete optimization report for a table
     *
     * @return array{
     *     table_name: string,
     *     current_indexes: array,
     *     unused_indexes: array,
     *     duplicate_indexes: array,
     *     redundant_indexes: array,
     *     recommended_indexes: array<IndexRecommendation>,
     *     total_removable: int,
     *     total_recommended: int,
     *     estimated_space_savings: string,
     *     migration_preview: string
     * }
     */
    public function analyzeTable(string $tableName, int $unusedDaysThreshold = 30): array
    {
        // Get current indexes
        $currentIndexes = $this->analyzer->getTableIndexes($tableName);

        // Find indexes to remove
        $unusedReport = $this->unusedDetector->getUnusedIndexReport($tableName, $unusedDaysThreshold);

        // Generate recommendations for new indexes
        $recommendations = $this->compositeGenerator->generateRecommendations($tableName);

        // Generate migration preview
        $migrationPreview = '';
        if (!empty($recommendations) || !empty($unusedReport['unused'])) {
            $migrationPreview = $this->migrationGenerator->generateOptimizationMigration(
                toAdd: $recommendations,
                toRemove: $unusedReport['unused'],
                tableName: $tableName
            );
        }

        return [
            'table_name' => $tableName,
            'current_indexes' => $currentIndexes,
            'unused_indexes' => $unusedReport['unused'],
            'duplicate_indexes' => $unusedReport['duplicates'],
            'redundant_indexes' => $unusedReport['redundant'],
            'recommended_indexes' => array_map(fn($r) => $r->toArray(), $recommendations),
            'total_removable' => $unusedReport['total_removable'],
            'total_recommended' => count($recommendations),
            'estimated_space_savings' => $unusedReport['estimated_space_savings'],
            'migration_preview' => $migrationPreview
        ];
    }

    /**
     * Generate and save optimization migration for a table
     */
    public function generateOptimizationMigration(string $tableName, int $unusedDaysThreshold = 30): string
    {
        $analysis = $this->analyzeTable($tableName, $unusedDaysThreshold);

        if ($analysis['total_removable'] === 0 && $analysis['total_recommended'] === 0) {
            throw new \RuntimeException("No index optimizations found for table '{$tableName}'");
        }

        $migration = $analysis['migration_preview'];
        $path = $this->migrationGenerator->saveMigration($migration);

        return $path;
    }

    /**
     * Get usage statistics for all indexes on a table
     *
     * @return array<array{
     *     index_name: string,
     *     usage_count: int,
     *     efficiency: float,
     *     days_since_last_use: int,
     *     selectivity: float
     * }>
     */
    public function getIndexStatistics(string $tableName): array
    {
        $metrics = $this->usageTracker->getTableUsageMetrics($tableName);

        return array_map(fn($m) => [
            'index_name' => $m->indexName->toString(),
            'usage_count' => $m->usageCount,
            'efficiency' => $m->getEfficiency(),
            'days_since_last_use' => $m->getDaysSinceLastUse(),
            'selectivity' => $m->selectivity,
            'is_unused' => $m->isUnused()
        ], $metrics);
    }

    /**
     * Get high-priority index recommendations across all tables
     *
     * @return array<array{
     *     table_name: string,
     *     recommendations: array<IndexRecommendation>
     * }>
     */
    public function getHighPriorityRecommendations(array $tableNames): array
    {
        $allRecommendations = [];

        foreach ($tableNames as $tableName) {
            $recommendations = $this->compositeGenerator->generateRecommendations($tableName);

            $highPriority = array_filter($recommendations, function(IndexRecommendation $r) {
                return in_array($r->priority->value, ['critical', 'high']);
            });

            if (!empty($highPriority)) {
                $allRecommendations[] = [
                    'table_name' => $tableName,
                    'recommendations' => array_map(fn($r) => $r->toArray(), $highPriority)
                ];
            }
        }

        return $allRecommendations;
    }

    /**
     * Quick health check for index optimization opportunities
     *
     * @return array{
     *     total_tables_analyzed: int,
     *     tables_with_unused_indexes: array<string>,
     *     tables_with_recommendations: array<string>,
     *     total_removable_indexes: int,
     *     total_recommended_indexes: int,
     *     requires_attention: bool
     * }
     */
    public function healthCheck(array $tableNames, int $unusedDaysThreshold = 30): array
    {
        $tablesWithUnused = [];
        $tablesWithRecommendations = [];
        $totalRemovable = 0;
        $totalRecommended = 0;

        foreach ($tableNames as $tableName) {
            $analysis = $this->analyzeTable($tableName, $unusedDaysThreshold);

            if ($analysis['total_removable'] > 0) {
                $tablesWithUnused[] = $tableName;
                $totalRemovable += $analysis['total_removable'];
            }

            if ($analysis['total_recommended'] > 0) {
                $tablesWithRecommendations[] = $tableName;
                $totalRecommended += $analysis['total_recommended'];
            }
        }

        return [
            'total_tables_analyzed' => count($tableNames),
            'tables_with_unused_indexes' => $tablesWithUnused,
            'tables_with_recommendations' => $tablesWithRecommendations,
            'total_removable_indexes' => $totalRemovable,
            'total_recommended_indexes' => $totalRecommended,
            'requires_attention' => $totalRemovable > 0 || $totalRecommended > 0
        ];
    }
}
