<?php

declare(strict_types=1);

namespace App\Domain\WebServer\Services;

use App\Domain\Domain\Models\Domain;
use App\Domain\WebServer\Contracts\WebServerAdapter;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * WebServerManager — install + switch + migrate işlemlerini orchestrate eder.
 *
 * Sistem akışı (Apache → OpenLiteSpeed geçiş örneği):
 *   1. preflight()        — yeni adapter kurulu mu? configtest geçiyor mu?
 *   2. createMigrationPlan() — hangi domain'ler taşınacak, hangi config'ler değişir
 *   3. migrate()          — vhost'ları yeni adapter'da oluştur (eski hala çalışır)
 *   4. switchAdapter()    — config('webserver.driver') güncelle
 *   5. cutover()          — eski adapter durdur, yeni adapter başlat
 *
 * Audit: her adım license_audit_log + audit_log tablolarına yazılır.
 */
class WebServerManager
{
    public function __construct(private readonly WebServerFactory $factory) {}

    /**
     * Yeni adapter'ı kur (paket yöneticisi üzerinden).
     */
    public function install(string $driver): array
    {
        $adapter = $this->factory->makeByKey($driver);
        if (! $adapter) {
            return ['ok' => false, 'error' => "Bilinmeyen driver: $driver"];
        }

        if ($adapter->isInstalled()) {
            return ['ok' => true, 'message' => $adapter->name() . ' zaten kurulu', 'already_installed' => true];
        }

        $this->logAudit('webserver.install.start', ['driver' => $driver]);

        $result = $adapter->install();

        $this->logAudit(
            $result['ok'] ? 'webserver.install.success' : 'webserver.install.failed',
            ['driver' => $driver, 'output' => substr($result['output'] ?? '', 0, 500)]
        );

        return $result;
    }

    /**
     * Aktif adapter'ı değiştir (kurulu olması şart).
     * Aktif vhost'lar yeni adapter'da yeniden oluşturulur.
     */
    public function switchTo(string $newDriver, bool $migrateVhosts = true): array
    {
        $newAdapter = $this->factory->makeByKey($newDriver);
        if (! $newAdapter) {
            return ['ok' => false, 'error' => "Bilinmeyen driver: $newDriver"];
        }

        // Preflight: kurulu mu?
        if (! $newAdapter->isInstalled()) {
            return [
                'ok' => false,
                'error' => $newAdapter->name() . ' kurulu değil. Önce kurulum yapın.',
                'requires_install' => true,
            ];
        }

        $currentDriver = (string) config('webserver.driver', 'apache');
        if ($currentDriver === $newDriver) {
            return ['ok' => true, 'message' => 'Zaten aktif: ' . $newAdapter->name(), 'no_change' => true];
        }

        $oldAdapter = $this->factory->makeByKey($currentDriver);

        $this->logAudit('webserver.switch.start', [
            'from' => $currentDriver,
            'to' => $newDriver,
            'migrate_vhosts' => $migrateVhosts,
        ]);

        try {
            // 1. Vhost migration (eski hala çalışıyor)
            $migratedCount = 0;
            if ($migrateVhosts) {
                $migratedCount = $this->migrateVhosts($newAdapter);
            }

            // 2. Yeni adapter config test
            $configTest = $newAdapter->configTest();
            if (! $configTest['ok']) {
                throw new \RuntimeException('Config test başarısız: ' . $configTest['output']);
            }

            // 3. Yeni adapter'ı başlat + enable
            $newAdapter->enable();
            $newAdapter->start();

            // 4. Eski adapter'ı durdur (varsa)
            if ($oldAdapter && $oldAdapter->isInstalled() && $oldAdapter->isRunning()) {
                $oldAdapter->stop();
                $oldAdapter->disable();
            }

            // 5. Driver setting güncelle (DB)
            $this->persistDriver($newDriver);

            $this->logAudit('webserver.switch.success', [
                'from' => $currentDriver,
                'to' => $newDriver,
                'vhosts_migrated' => $migratedCount,
            ]);

            return [
                'ok' => true,
                'message' => "Aktif web sunucusu artık {$newAdapter->name()}. {$migratedCount} vhost taşındı.",
                'vhosts_migrated' => $migratedCount,
                'new_driver' => $newDriver,
            ];
        } catch (\Throwable $e) {
            $this->logAudit('webserver.switch.failed', [
                'from' => $currentDriver,
                'to' => $newDriver,
                'error' => $e->getMessage(),
            ]);

            return ['ok' => false, 'error' => $e->getMessage()];
        }
    }

    /**
     * Vhost'ları yeni adapter'a taşı (eski silinmez — rollback için).
     */
    private function migrateVhosts(WebServerAdapter $newAdapter): int
    {
        if (! \Schema::hasTable('domains')) {
            return 0;
        }

        $count = 0;
        Domain::query()
            ->with('account')
            ->where('status', 'active')
            ->chunk(50, function ($domains) use ($newAdapter, &$count) {
                foreach ($domains as $domain) {
                    try {
                        $newAdapter->createVhost($domain);
                        $count++;
                    } catch (\Throwable $e) {
                        Log::warning('Vhost migration failed', [
                            'domain' => $domain->name,
                            'adapter' => $newAdapter->key(),
                            'error' => $e->getMessage(),
                        ]);
                    }
                }
            });

        return $count;
    }

    /**
     * Aktif driver'ı kalıcı olarak kaydet.
     */
    private function persistDriver(string $driver): void
    {
        if (\Schema::hasTable('server_settings')) {
            DB::table('server_settings')->updateOrInsert(
                ['key' => 'webserver_driver'],
                [
                    'group' => 'webserver',
                    'type' => 'string',
                    'value' => $driver,
                    'updated_at' => now(),
                    'created_at' => now(),
                ]
            );
        }

        // Config cache temizle ki yeni driver hemen aktif olsun
        try {
            \Artisan::call('config:clear');
        } catch (\Throwable) {
            // Cache temizliği başarısız olsa bile devam
        }
    }

    /**
     * Audit log — license_audit_log tablosuna yazar.
     */
    private function logAudit(string $action, array $payload): void
    {
        try {
            if (\Schema::hasTable('license_audit_log')) {
                DB::table('license_audit_log')->insert([
                    'action' => $action,
                    'payload' => json_encode($payload, JSON_UNESCAPED_UNICODE),
                    'success' => ! str_contains($action, 'failed'),
                    'remote_ip' => request()?->ip(),
                    'occurred_at' => now(),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            }
        } catch (\Throwable) {
            Log::info("[webserver-audit] $action", $payload);
        }
    }
}
