<?php

namespace App\Services;

use App\Models\Amministratore;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * Servizio per gestione distribuzione multi-server degli archivi amministratori
 */
class DistributionService
{
    /**
     * Migra un amministratore da un server all'altro
     */
    public static function migrateAdministrator(Amministratore $amministratore, string $targetServerUrl): array
    {
        try {
            Log::info("Inizio migrazione amministratore {$amministratore->codice_amministratore} verso {$targetServerUrl}");

            // 1. Prepara archivio per migrazione
            $migrationData = $amministratore->prepareForMigration();
            if (!$migrationData['success']) {
                throw new \Exception('Errore preparazione migrazione: ' . $migrationData['error']);
            }

            // 2. Verifica connettività server target
            $targetHealth = static::checkServerHealth($targetServerUrl);
            if (!$targetHealth['success']) {
                throw new \Exception('Server target non raggiungibile: ' . $targetHealth['error']);
            }

            // 3. Trasferisce archivio al server target
            $transferResult = static::transferArchive($migrationData['zip_file'], $targetServerUrl, $amministratore);
            if (!$transferResult['success']) {
                throw new \Exception('Errore trasferimento archivio: ' . $transferResult['error']);
            }

            // 4. Aggiorna configurazione amministratore
            $amministratore->update([
                'server_database' => parse_url($targetServerUrl, PHP_URL_HOST),
                'server_port' => parse_url($targetServerUrl, PHP_URL_PORT) ?: 3306,
                'url_accesso' => $targetServerUrl,
                'stato_sincronizzazione' => 'migrazione',
                'ultimo_backup' => now()
            ]);

            // 5. Notifica server target per attivazione
            $activationResult = static::activateOnTargetServer($targetServerUrl, $amministratore);
            
            if ($activationResult['success']) {
                $amministratore->update(['stato_sincronizzazione' => 'attivo']);
                
                Log::info("Migrazione completata per amministratore {$amministratore->codice_amministratore}");
                
                return [
                    'success' => true,
                    'message' => 'Migrazione completata con successo',
                    'new_url' => $targetServerUrl,
                    'transfer_id' => $transferResult['transfer_id'] ?? null
                ];
            } else {
                throw new \Exception('Errore attivazione su server target: ' . $activationResult['error']);
            }

        } catch (\Exception $e) {
            Log::error("Errore migrazione amministratore {$amministratore->codice_amministratore}: " . $e->getMessage());
            
            // Ripristina stato precedente
            $amministratore->update(['stato_sincronizzazione' => 'errore']);
            
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Verifica salute e compatibilità di un server NetGesCon
     */
    public static function checkServerHealth(string $serverUrl): array
    {
        try {
            $response = Http::timeout(10)->get("{$serverUrl}/api/health");
            
            if (!$response->successful()) {
                throw new \Exception("Server risponde con codice {$response->status()}");
            }

            $data = $response->json();
            
            // Verifica versione compatibile
            $requiredVersion = config('app.min_version', '1.0.0');
            if (version_compare($data['version'] ?? '0.0.0', $requiredVersion, '<')) {
                throw new \Exception("Versione server incompatibile: {$data['version']} < {$requiredVersion}");
            }

            return [
                'success' => true,
                'server_info' => $data,
                'compatible' => true
            ];

        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage(),
                'compatible' => false
            ];
        }
    }

    /**
     * Trasferisce archivio amministratore a server target
     */
    private static function transferArchive(string $zipPath, string $targetServerUrl, Amministratore $amministratore): array
    {
        try {
            $response = Http::timeout(300)
                ->attach('archive', file_get_contents($zipPath), basename($zipPath))
                ->post("{$targetServerUrl}/api/import-administrator", [
                    'codice_amministratore' => $amministratore->codice_amministratore,
                    'source_server' => config('app.url'),
                    'migration_token' => static::generateMigrationToken($amministratore)
                ]);

            if (!$response->successful()) {
                throw new \Exception("Errore HTTP {$response->status()}: " . $response->body());
            }

            return $response->json();

        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Attiva amministratore su server target
     */
    private static function activateOnTargetServer(string $targetServerUrl, Amministratore $amministratore): array
    {
        try {
            $response = Http::timeout(60)->post("{$targetServerUrl}/api/activate-administrator", [
                'codice_amministratore' => $amministratore->codice_amministratore,
                'activation_token' => static::generateMigrationToken($amministratore)
            ]);

            if (!$response->successful()) {
                throw new \Exception("Errore attivazione HTTP {$response->status()}: " . $response->body());
            }

            return $response->json();

        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Genera token sicuro per migrazione
     */
    private static function generateMigrationToken(Amministratore $amministratore): string
    {
        return hash('sha256', $amministratore->codice_amministratore . $amministratore->created_at . config('app.key'));
    }

    /**
     * Sincronizza dati tra server per amministratore distribuito
     */
    public static function syncAdministratorData(Amministratore $amministratore): array
    {
        try {
            if (!$amministratore->server_database) {
                return ['success' => true, 'message' => 'Amministratore su server locale'];
            }

            $targetUrl = $amministratore->url_accesso;
            if (!$targetUrl) {
                throw new \Exception('URL server target non configurato');
            }

            // Verifica stato server target
            $healthCheck = static::checkServerHealth($targetUrl);
            if (!$healthCheck['success']) {
                throw new \Exception('Server target non raggiungibile');
            }

            // Invia richiesta di sincronizzazione
            $response = Http::timeout(30)->post("{$targetUrl}/api/sync-administrator", [
                'codice_amministratore' => $amministratore->codice_amministratore,
                'last_sync' => $amministratore->updated_at,
                'sync_token' => static::generateMigrationToken($amministratore)
            ]);

            if (!$response->successful()) {
                throw new \Exception("Errore sincronizzazione: {$response->status()}");
            }

            $syncData = $response->json();
            
            // Aggiorna timestamp ultima sincronizzazione
            $amministratore->touch();

            return [
                'success' => true,
                'synced_at' => now(),
                'changes' => $syncData['changes'] ?? 0
            ];

        } catch (\Exception $e) {
            Log::error("Errore sincronizzazione amministratore {$amministratore->codice_amministratore}: " . $e->getMessage());
            
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Ottiene statistiche distribuzione server
     */
    public static function getDistributionStats(): array
    {
        $stats = [
            'total_administrators' => Amministratore::count(),
            'local_administrators' => Amministratore::whereNull('server_database')->count(),
            'distributed_administrators' => Amministratore::whereNotNull('server_database')->count(),
            'servers' => [],
            'status_distribution' => Amministratore::groupBy('stato_sincronizzazione')
                ->selectRaw('stato_sincronizzazione, count(*) as count')
                ->pluck('count', 'stato_sincronizzazione')
                ->toArray()
        ];

        // Raggruppa per server
        $serverGroups = Amministratore::whereNotNull('server_database')
            ->groupBy('server_database')
            ->selectRaw('server_database, count(*) as administrators_count')
            ->get();

        foreach ($serverGroups as $group) {
            $stats['servers'][] = [
                'server' => $group->server_database,
                'administrators_count' => $group->administrators_count,
                'health' => 'unknown' // TODO: implementare controllo salute periodico
            ];
        }

        return $stats;
    }

    /**
     * Routing DNS intelligente per amministratori distribuiti
     */
    public static function getAdministratorAccessUrl(string $codiceAmministratore): array
    {
        $amministratore = Amministratore::where('codice_amministratore', $codiceAmministratore)->first();
        
        if (!$amministratore) {
            return [
                'success' => false,
                'error' => 'Amministratore non trovato'
            ];
        }

        // Se ha URL specifico, usalo
        if ($amministratore->url_accesso) {
            return [
                'success' => true,
                'url' => $amministratore->url_accesso,
                'server_type' => 'distributed',
                'server' => $amministratore->server_database
            ];
        }

        // Altrimenti è su server locale
        return [
            'success' => true,
            'url' => config('app.url'),
            'server_type' => 'local',
            'server' => 'localhost'
        ];
    }

    /**
     * Backup automatico distribuito
     */
    public static function performDistributedBackup(Amministratore $amministratore): array
    {
        try {
            // Backup locale
            $localBackup = $amministratore->createDatabaseBackup();
            if (!$localBackup['success']) {
                throw new \Exception('Errore backup locale: ' . $localBackup['error']);
            }

            // Se distribuito, backup anche remoto
            if ($amministratore->server_database && $amministratore->url_accesso) {
                $remoteBackup = static::triggerRemoteBackup($amministratore);
                
                return [
                    'success' => true,
                    'local_backup' => $localBackup,
                    'remote_backup' => $remoteBackup
                ];
            }

            return [
                'success' => true,
                'local_backup' => $localBackup,
                'remote_backup' => null
            ];

        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Trigger backup remoto
     */
    private static function triggerRemoteBackup(Amministratore $amministratore): array
    {
        try {
            $response = Http::timeout(120)->post("{$amministratore->url_accesso}/api/backup-administrator", [
                'codice_amministratore' => $amministratore->codice_amministratore,
                'backup_token' => static::generateMigrationToken($amministratore)
            ]);

            if (!$response->successful()) {
                throw new \Exception("Errore backup remoto: {$response->status()}");
            }

            return $response->json();

        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
}
