<?php
declare(strict_types=1);

namespace App\Controllers;

use App\Core\Controller;
use App\Models\AppMetaModel;
use App\Core\Database;
use Throwable;

final class InstallerController extends Controller
{
    private function lockFile(): string
    {
        return storage_path('system/install.lock');
    }

    private function isInstalled(): bool
    {
        return is_file($this->lockFile());
    }

    public function install(): void
    {
        if ($this->isInstalled()) {
            $this->view('installer/install', [
                'installed' => true,
                'checks' => $this->checks(),
            ]);
            return;
        }

        if ($this->isPost()) {
            csrf_check();

            $errors = $this->checks(false);
            $hasFail = false;
            foreach ($errors as $row) {
                if (empty($row['ok'])) {
                    $hasFail = true;
                    break;
                }
            }

            if (!$hasFail) {
                ensure_dir(dirname($this->lockFile()));
                file_put_contents($this->lockFile(), date('c'));

                try {
                    (new AppMetaModel())->set('app_version', '15');
                    (new AppMetaModel())->set('installed_at', date('Y-m-d H:i:s'));
                } catch (Throwable $e) {
                }

                flash('success', trans('installation_completed'));
                redirect('login');
            }

            flash('danger', 'Installer checks failed.');
        }

        $this->view('installer/install', [
            'installed' => false,
            'checks' => $this->checks(),
        ]);
    }

    public function upgrade(): void
    {
        require_permission('upgrade.run');

        if ($this->isPost()) {
            csrf_check();

            try {
                (new AppMetaModel())->set('app_version', '15');
                flash('success', trans('upgrade_completed'));
            } catch (Throwable $e) {
                flash('danger', $e->getMessage());
            }

            redirect('admin/system');
        }

        $this->view('installer/upgrade', [
            'checks' => $this->checks(),
            'currentVersion' => (new AppMetaModel())->get('app_version', 'unknown'),
            'targetVersion' => '15',
        ]);
    }

    private function checks(bool $withMessages = true): array
    {
        return [
            [
                'label' => trans('php_version'),
                'ok' => version_compare(PHP_VERSION, '8.1.0', '>='),
                'value' => PHP_VERSION,
            ],
            [
                'label' => trans('pdo_mysql'),
                'ok' => extension_loaded('pdo_mysql'),
                'value' => extension_loaded('pdo_mysql') ? 'loaded' : 'missing',
            ],
            [
                'label' => trans('mbstring_extension'),
                'ok' => extension_loaded('mbstring'),
                'value' => extension_loaded('mbstring') ? 'loaded' : 'missing',
            ],
            [
                'label' => trans('zip_extension'),
                'ok' => extension_loaded('zip'),
                'value' => extension_loaded('zip') ? 'loaded' : 'missing',
            ],
            [
                'label' => trans('storage_dir'),
                'ok' => is_dir(storage_path()) && is_writable(storage_path()),
                'value' => storage_path(),
            ],
            [
                'label' => trans('db_connection'),
                'ok' => $this->dbCheck(),
                'value' => $this->dbCheck() ? 'connected' : 'failed',
            ],
        ];
    }

    private function dbCheck(): bool
    {
        try {
            $db = Database::getInstance();
            $db->query('SELECT 1');
            return true;
        } catch (Throwable $e) {
            return false;
        }
    }
}
