<?php

declare(strict_types=1);

namespace App\Domain\AppInstaller\Services;

use App\Domain\Account\Models\Account;
use App\Domain\AppInstaller\Catalog\AppCatalog;
use App\Domain\AppInstaller\Models\InstalledApp;
use App\Domain\Database\Models\MysqlDatabase;
use App\Domain\Database\Services\DatabaseProvisioner;
use App\Domain\Domain\Models\Domain;
use App\Domain\Sysapi\Contracts\SysapiBridge;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use RuntimeException;

/**
 * Otomatik uygulama yükleyici.
 *
 * Phase 1: kayıt + sysapi onx-app-install çağrısı (mock'ta hemen 'active' olur).
 * Phase 1.5: gerçek wget/tar + DB import + .env render.
 * Phase 2: tek-tıkla update, otomatik update kontrolü.
 */
final class AppInstallerService
{
    public function __construct(
        private readonly SysapiBridge $sysapi,
        private readonly DatabaseProvisioner $dbProvisioner,
    ) {}

    /**
     * @param  array<string, mixed>  $config
     */
    public function install(Account $account, string $appSlug, array $config): InstalledApp
    {
        $catalog = AppCatalog::find($appSlug);
        if (! $catalog) {
            throw new RuntimeException("Uygulama bulunamadı: {$appSlug}");
        }

        // Domain doğrulama
        $domainId = $config['domain_id'] ?? null;
        if (! $domainId) {
            throw new RuntimeException('Domain seçimi zorunlu.');
        }
        $domain = Domain::where('id', $domainId)->where('account_id', $account->id)->first();
        if (! $domain) {
            throw new RuntimeException('Domain bu hesaba ait değil.');
        }

        // Install path validation
        $path = $config['install_path'] ?? '/';
        $path = '/'.trim($path, '/');
        if (! preg_match('#^/[a-zA-Z0-9_/-]*$#', $path)) {
            throw new RuntimeException('Geçersiz kurulum yolu.');
        }

        // Çakışma kontrolü
        $exists = InstalledApp::where('account_id', $account->id)
            ->where('domain_id', $domain->id)
            ->where('install_path', $path)
            ->whereNull('deleted_at')
            ->exists();
        if ($exists) {
            throw new RuntimeException("Bu konumda zaten bir uygulama var: {$domain->name}{$path}");
        }

        // Version
        $version = $config['version'] ?? $catalog['latest_version'];
        if (! in_array($version, $catalog['available_versions'], true)) {
            $version = $catalog['latest_version'];
        }

        // DB oluştur (gerekirse)
        $databaseId = null;
        if (! empty($catalog['requires_db'])) {
            $dbName = $appSlug.'_'.substr(Str::random(6), 0, 6);
            $database = $this->dbProvisioner->createDatabase($account, strtolower($dbName));
            $databaseId = $database->id;
        }

        // URL build
        $url = ($domain->ssl_enabled ? 'https://' : 'http://').$domain->name.($path === '/' ? '' : $path);

        $app = DB::transaction(fn () => InstalledApp::create([
            'account_id' => $account->id,
            'domain_id' => $domain->id,
            'app_type' => $appSlug,
            'version' => $version,
            'install_url' => $url,
            'install_path' => $path,
            'database_id' => $databaseId,
            'admin_username' => $config['admin_username'] ?? 'admin',
            'admin_email' => $config['admin_email'] ?? $account->email,
            'admin_password_hash' => isset($config['admin_password']) ? password_hash($config['admin_password'], PASSWORD_BCRYPT) : null,
            'site_title' => $config['site_title'] ?? $catalog['name'],
            'language' => $config['language'] ?? 'tr_TR',
            'config_overrides' => $config['config_overrides'] ?? [],
            'status' => 'installing',
        ]));

        // Sysapi çağrısı (mock'ta hemen başarılı)
        $result = $this->sysapi->run('app-install', [
            'app' => $appSlug,
            'version' => $version,
            'username' => $account->username,
            'domain' => $domain->name,
            'path' => $path,
            'db_name' => $databaseId ? MysqlDatabase::find($databaseId)?->real_db_name : null,
            'admin_user' => $app->admin_username,
            'admin_email' => $app->admin_email,
            'admin_password' => $config['admin_password'] ?? null,
            'site_title' => $app->site_title,
            'language' => $app->language,
        ]);

        if ($result->failed()) {
            $app->update(['status' => 'failed', 'last_error' => $result->stderr]);
            throw new RuntimeException("Kurulum başarısız: {$result->stderr}");
        }

        $app->update([
            'status' => 'active',
            'installed_at' => now(),
            'last_error' => null,
        ]);

        return $app->fresh();
    }

    public function uninstall(InstalledApp $app, bool $deleteDatabase = false): void
    {
        $app->update(['status' => 'uninstalling']);

        $result = $this->sysapi->run('app-uninstall', [
            'app' => $app->app_type,
            'username' => $app->account->username,
            'domain' => $app->domain?->name,
            'path' => $app->install_path,
            'delete_db' => $deleteDatabase,
        ]);

        if ($result->failed()) {
            $app->update(['status' => 'failed', 'last_error' => $result->stderr]);
            throw new RuntimeException("Kaldırma başarısız: {$result->stderr}");
        }

        if ($deleteDatabase && $app->database) {
            try {
                $this->dbProvisioner->deleteDatabase($app->database);
            } catch (\Throwable $e) {
                // DB silme başarısız olsa bile app silindi sayılır, log yeterli
            }
        }

        $app->delete();
    }
}
