<?php

use App\Models\User;
use App\Services\Install\EnvironmentFileWriter;
use App\Services\Install\InstallationStatus;
use App\Services\WorkspaceBootstrapService;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Volt\Component;

new #[Layout('layouts.install')] class extends Component
{
    public int $step = 1;

    public string $app_name = '';

    public string $app_url = '';

    public string $app_env = 'production';

    public bool $app_debug = false;

    public string $db_connection = 'mysql';

    public string $db_host = '127.0.0.1';

    public string $db_port = '3306';

    public string $db_database = '';

    public string $db_username = '';

    public string $db_password = '';

    public string $db_sqlite_path = 'database/database.sqlite';

    public string $migrateOutput = '';

    public string $admin_name = '';

    public string $admin_email = '';

    public string $admin_password = '';

    public string $admin_password_confirmation = '';

    public string $workspace_name = 'My Collabs';

    public function mount(): void
    {
        if (InstallationStatus::isComplete()) {
            abort(404);
        }

        $this->app_name = (string) config('app.name', 'Collabs');
        $this->app_url = (string) config('app.url', url('/'));
    }

    public function continueFromWelcome(): void
    {
        $this->step = 2;
    }

    public function saveEnvironment(): void
    {
        $rules = [
            'app_name' => ['required', 'string', 'max:255'],
            'app_url' => ['required', 'url'],
            'app_env' => ['required', 'in:production,local,staging'],
            'app_debug' => ['boolean'],
            'db_connection' => ['required', 'in:mysql,sqlite'],
        ];

        if ($this->db_connection === 'mysql') {
            $rules['db_host'] = ['required', 'string', 'max:255'];
            $rules['db_port'] = ['required', 'string', 'max:8'];
            $rules['db_database'] = ['required', 'string', 'max:255'];
            $rules['db_username'] = ['required', 'string', 'max:255'];
            $rules['db_password'] = ['nullable', 'string', 'max:255'];
        } else {
            $rules['db_sqlite_path'] = ['required', 'string', 'max:255'];
        }

        $this->validate($rules);

        if ($this->db_connection === 'mysql' && ! extension_loaded('pdo_mysql')) {
            $this->addError('db_connection', __('The pdo_mysql PHP extension is required for MySQL. Enable it in cPanel → Select PHP Version → Extensions.'));

            return;
        }

        try {
            EnvironmentFileWriter::ensureFromExample();

            $sqliteAbsolute = null;
            if ($this->db_connection === 'sqlite') {
                $relative = trim($this->db_sqlite_path) ?: 'database/database.sqlite';
                $sqliteAbsolute = str_starts_with($relative, '/') ? $relative : base_path($relative);
                $dir = dirname($sqliteAbsolute);
                if (! is_dir($dir)) {
                    mkdir($dir, 0755, true);
                }
                if (! is_file($sqliteAbsolute)) {
                    touch($sqliteAbsolute);
                }
                if (! is_writable($sqliteAbsolute)) {
                    $this->addError('db_sqlite_path', __('The SQLite database file must be writable by the web server.'));

                    return;
                }
            }

            $pairs = [
                'APP_NAME' => $this->app_name,
                'APP_ENV' => $this->app_env,
                'APP_DEBUG' => $this->app_debug,
                'APP_URL' => rtrim($this->app_url, '/'),
                'DB_CONNECTION' => $this->db_connection,
            ];

            if ($this->db_connection === 'mysql') {
                $pairs['DB_HOST'] = $this->db_host;
                $pairs['DB_PORT'] = $this->db_port;
                $pairs['DB_DATABASE'] = $this->db_database;
                $pairs['DB_USERNAME'] = $this->db_username;
                $pairs['DB_PASSWORD'] = $this->db_password;
            } else {
                $pairs['DB_DATABASE'] = $sqliteAbsolute ?? database_path('database.sqlite');
            }

            EnvironmentFileWriter::setMany($pairs);

            Artisan::call('key:generate', ['--force' => true]);
            Artisan::call('config:clear');

            $this->step = 3;
        } catch (\Throwable $e) {
            $this->addError('environment', $e->getMessage());
        }
    }

    public function runMigrations(): void
    {
        $this->migrateOutput = '';
        $this->resetErrorBag('migrate');

        try {
            Artisan::call('config:clear');
            DB::purge();
            DB::reconnect();
            DB::connection()->getPdo();
        } catch (\Throwable $e) {
            $this->addError('migrate', __('Could not connect to the database: :message', ['message' => $e->getMessage()]));

            return;
        }

        try {
            Artisan::call('migrate', ['--force' => true]);
            $this->migrateOutput = trim(Artisan::output()) ?: __('Migrations finished.');
            $this->step = 4;
        } catch (\Throwable $e) {
            $this->addError('migrate', $e->getMessage());
        }
    }

    public function createAdmin(WorkspaceBootstrapService $workspaceBootstrap): void
    {
        $this->validate([
            'admin_name' => ['required', 'string', 'max:255'],
            'admin_email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
            'admin_password' => ['required', 'string', 'confirmed', Password::defaults()],
            'workspace_name' => ['required', 'string', 'max:255'],
        ]);

        try {
            $user = User::query()->create([
                'name' => $this->admin_name,
                'email' => $this->admin_email,
                'password' => Hash::make($this->admin_password),
                'email_verified_at' => now(),
            ]);

            $workspaceBootstrap->bootstrap($user, $this->workspace_name);

            EnvironmentFileWriter::setMany([
                'SUPER_ADMIN_USER_IDS' => (string) $user->id,
            ]);

            Artisan::call('config:clear');

            try {
                Artisan::call('storage:link');
            } catch (\Throwable) {
                //
            }

            InstallationStatus::markComplete();

            $this->step = 5;
        } catch (\Throwable $e) {
            $this->addError('admin', $e->getMessage());
        }
    }

    #[Computed]
    public function requirements(): array
    {
        $ext = ['ctype', 'curl', 'dom', 'fileinfo', 'filter', 'mbstring', 'openssl', 'pdo', 'session', 'tokenizer', 'xml', 'json'];
        $rows = [
            [
                'label' => 'PHP '.PHP_VERSION.' (8.3+)',
                'ok' => version_compare(PHP_VERSION, '8.3.0', '>='),
            ],
            [
                'label' => __('Composer dependencies (vendor/)'),
                'ok' => is_file(base_path('vendor/autoload.php')),
                'hint' => __('Shipped inside the cPanel ZIP from scripts/package-for-cpanel.sh or the GitHub “Package for cPanel” workflow—not from a plain git clone.'),
            ],
            [
                'label' => __('storage/ is writable'),
                'ok' => is_writable(storage_path()),
            ],
            [
                'label' => __('bootstrap/cache/ is writable'),
                'ok' => is_writable(base_path('bootstrap/cache')),
            ],
            [
                'label' => __('storage/framework/sessions is writable'),
                'ok' => is_writable(storage_path('framework/sessions')),
            ],
        ];

        foreach ($ext as $name) {
            $rows[] = [
                'label' => "ext-{$name}",
                'ok' => extension_loaded($name),
            ];
        }

        $rows[] = [
            'label' => __('Vite build (public/build/manifest.json)'),
            'ok' => is_file(public_path('build/manifest.json')),
            'warn' => true,
            'hint' => __('Included in the cPanel ZIP from scripts/package-for-cpanel.sh or GitHub Actions—you do not run npm on the server.'),
        ];

        return $rows;
    }

    #[Computed]
    public function requirementsPass(): bool
    {
        foreach ($this->requirements as $row) {
            if (empty($row['warn']) && ! $row['ok']) {
                return false;
            }
        }

        return true;
    }
}; ?>

<div class="space-y-6">
    @if ($step === 1)
        <div>
            <h1 class="text-xl font-semibold text-foreground">{{ __('Install Collabs') }}</h1>
            <p class="mt-2 text-sm text-muted-foreground leading-relaxed">
                {{ __('Run this once after uploading the cPanel release ZIP (includes vendor/ and public/build/). Plain git clone is not enough—see docs/CPANEL.md. When finished, you may remove the installer files listed on the last step.') }}
            </p>
        </div>

        <ul class="space-y-2 rounded-xl border border-border/60 bg-card/30 p-4 text-sm">
            @foreach ($this->requirements as $row)
                <li class="flex items-start gap-2">
                    @if ($row['ok'])
                        <span class="mt-0.5 text-success" aria-hidden="true">✓</span>
                    @elseif (!empty($row['warn']))
                        <span class="mt-0.5 text-amber-600 dark:text-amber-400" aria-hidden="true">!</span>
                    @else
                        <span class="mt-0.5 text-destructive" aria-hidden="true">✕</span>
                    @endif
                    <span class="@if(!$row['ok'] && empty($row['warn'])) text-destructive @elseif(!empty($row['warn']) && !$row['ok']) text-amber-700 dark:text-amber-300 @else text-foreground @endif">
                        {{ $row['label'] }}
                        @if (! $row['ok'] && ! empty($row['hint']))
                            <span class="block text-xs text-muted-foreground font-normal">{{ $row['hint'] }}</span>
                        @elseif (!empty($row['warn']) && ! $row['ok'])
                            <span class="block text-xs text-muted-foreground font-normal">{{ __('Build the cPanel ZIP locally or via GitHub Actions (see docs/CPANEL.md)—do not use a raw git clone without vendor/ and public/build/.') }}</span>
                        @endif
                    </span>
                </li>
            @endforeach
        </ul>

        @if (! $this->requirementsPass)
            <p class="text-sm text-destructive">{{ __('Fix the failed checks above, then refresh this page.') }}</p>
        @endif

        <div class="flex justify-end">
            <button
                type="button"
                wire:click="continueFromWelcome"
                @disabled(! $this->requirementsPass)
                class="inline-flex items-center justify-center rounded-xl bg-foreground px-5 py-2.5 text-sm font-semibold text-primary-foreground shadow-sm hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40"
            >
                {{ __('Continue') }}
            </button>
        </div>
    @endif

    @if ($step === 2)
        <div>
            <h1 class="text-xl font-semibold text-foreground">{{ __('Environment') }}</h1>
            <p class="mt-2 text-sm text-muted-foreground">{{ __('Writes to .env and generates APP_KEY.') }}</p>
        </div>

        <x-input-error :messages="$errors->get('environment')" class="text-sm" />

        <form wire:submit="saveEnvironment" class="space-y-4">
            <div>
                <x-input-label for="app_name" :value="__('App name')" />
                <x-text-input wire:model="app_name" id="app_name" class="mt-1.5 block w-full" type="text" required />
                <x-input-error :messages="$errors->get('app_name')" class="mt-2" />
            </div>
            <div>
                <x-input-label for="app_url" :value="__('App URL')" />
                <x-text-input wire:model="app_url" id="app_url" class="mt-1.5 block w-full" type="url" required placeholder="https://yourdomain.com" />
                <x-input-error :messages="$errors->get('app_url')" class="mt-2" />
            </div>
            <div>
                <x-input-label for="app_env" :value="__('Environment')" />
                <select wire:model.live="app_env" id="app_env" class="mt-1.5 block w-full rounded-xl border-border bg-background text-sm shadow-sm focus:border-accent focus:ring-accent">
                    <option value="production">production</option>
                    <option value="staging">staging</option>
                    <option value="local">local</option>
                </select>
            </div>
            <div class="flex items-center gap-2">
                <input wire:model="app_debug" id="app_debug" type="checkbox" class="rounded border-border text-foreground focus:ring-accent" />
                <x-input-label for="app_debug" :value="__('Enable debug (not recommended on production)')" class="!mb-0" />
            </div>

            <div>
                <x-input-label for="db_connection" :value="__('Database')" />
                <select wire:model.live="db_connection" id="db_connection" class="mt-1.5 block w-full rounded-xl border-border bg-background text-sm shadow-sm focus:border-accent focus:ring-accent">
                    <option value="mysql">MySQL / MariaDB (cPanel)</option>
                    <option value="sqlite">SQLite</option>
                </select>
                <x-input-error :messages="$errors->get('db_connection')" class="mt-2" />
            </div>

            @if ($db_connection === 'mysql')
                <div class="grid gap-4 sm:grid-cols-2">
                    <div class="sm:col-span-2">
                        <x-input-label for="db_host" :value="__('Host')" />
                        <x-text-input wire:model="db_host" id="db_host" class="mt-1.5 block w-full" type="text" required />
                        <x-input-error :messages="$errors->get('db_host')" class="mt-2" />
                    </div>
                    <div>
                        <x-input-label for="db_port" :value="__('Port')" />
                        <x-text-input wire:model="db_port" id="db_port" class="mt-1.5 block w-full" type="text" required />
                    </div>
                    <div>
                        <x-input-label for="db_database" :value="__('Database name')" />
                        <x-text-input wire:model="db_database" id="db_database" class="mt-1.5 block w-full" type="text" required autocomplete="off" />
                    </div>
                    <div>
                        <x-input-label for="db_username" :value="__('Username')" />
                        <x-text-input wire:model="db_username" id="db_username" class="mt-1.5 block w-full" type="text" required autocomplete="off" />
                    </div>
                    <div>
                        <x-input-label for="db_password" :value="__('Password')" />
                        <x-text-input wire:model="db_password" id="db_password" class="mt-1.5 block w-full" type="password" autocomplete="new-password" />
                    </div>
                </div>
            @else
                <div>
                    <x-input-label for="db_sqlite_path" :value="__('SQLite path (relative to project or absolute)')" />
                    <x-text-input wire:model="db_sqlite_path" id="db_sqlite_path" class="mt-1.5 block w-full" type="text" required />
                    <x-input-error :messages="$errors->get('db_sqlite_path')" class="mt-2" />
                </div>
            @endif

            <div class="flex justify-between gap-3 pt-2">
                <button type="button" wire:click="$set('step', 1)" class="rounded-xl border border-border bg-card px-4 py-2.5 text-sm font-medium text-foreground hover:bg-secondary/50">
                    {{ __('Back') }}
                </button>
                <button type="submit" class="rounded-xl bg-foreground px-5 py-2.5 text-sm font-semibold text-primary-foreground shadow-sm hover:opacity-90">
                    {{ __('Save & continue') }}
                </button>
            </div>
        </form>
    @endif

    @if ($step === 3)
        <div>
            <h1 class="text-xl font-semibold text-foreground">{{ __('Database setup') }}</h1>
            <p class="mt-2 text-sm text-muted-foreground">{{ __('Create tables (php artisan migrate --force).') }}</p>
        </div>

        <x-input-error :messages="$errors->get('migrate')" class="text-sm" />

        @if ($migrateOutput !== '')
            <pre class="max-h-48 overflow-auto rounded-lg bg-secondary/40 p-3 text-xs text-foreground whitespace-pre-wrap">{{ $migrateOutput }}</pre>
        @endif

        <div class="flex justify-between gap-3">
            <button type="button" wire:click="$set('step', 2)" class="rounded-xl border border-border bg-card px-4 py-2.5 text-sm font-medium text-foreground hover:bg-secondary/50">
                {{ __('Back') }}
            </button>
            <button type="button" wire:click="runMigrations" class="rounded-xl bg-foreground px-5 py-2.5 text-sm font-semibold text-primary-foreground shadow-sm hover:opacity-90">
                {{ __('Run migrations') }}
            </button>
        </div>
    @endif

    @if ($step === 4)
        <div>
            <h1 class="text-xl font-semibold text-foreground">{{ __('Administrator') }}</h1>
            <p class="mt-2 text-sm text-muted-foreground">{{ __('Creates the first user, default workspace, and grants super-admin (SUPER_ADMIN_USER_IDS in .env).') }}</p>
        </div>

        <x-input-error :messages="$errors->get('admin')" class="text-sm" />

        <form wire:submit="createAdmin" class="space-y-4">
            <div>
                <x-input-label for="workspace_name" :value="__('Workspace name')" />
                <x-text-input wire:model="workspace_name" id="workspace_name" class="mt-1.5 block w-full" type="text" required />
                <x-input-error :messages="$errors->get('workspace_name')" class="mt-2" />
            </div>
            <div>
                <x-input-label for="admin_name" :value="__('Name')" />
                <x-text-input wire:model="admin_name" id="admin_name" class="mt-1.5 block w-full" type="text" required autocomplete="name" />
                <x-input-error :messages="$errors->get('admin_name')" class="mt-2" />
            </div>
            <div>
                <x-input-label for="admin_email" :value="__('Email')" />
                <x-text-input wire:model="admin_email" id="admin_email" class="mt-1.5 block w-full" type="email" required autocomplete="username" />
                <x-input-error :messages="$errors->get('admin_email')" class="mt-2" />
            </div>
            <div>
                <x-input-label for="admin_password" :value="__('Password')" />
                <x-text-input wire:model="admin_password" id="admin_password" class="mt-1.5 block w-full" type="password" required autocomplete="new-password" />
                <x-input-error :messages="$errors->get('admin_password')" class="mt-2" />
            </div>
            <div>
                <x-input-label for="admin_password_confirmation" :value="__('Confirm password')" />
                <x-text-input wire:model="admin_password_confirmation" id="admin_password_confirmation" class="mt-1.5 block w-full" type="password" required autocomplete="new-password" />
            </div>

            <div class="flex justify-between gap-3 pt-2">
                <button type="button" wire:click="$set('step', 3)" class="rounded-xl border border-border bg-card px-4 py-2.5 text-sm font-medium text-foreground hover:bg-secondary/50">
                    {{ __('Back') }}
                </button>
                <button type="submit" class="rounded-xl bg-foreground px-5 py-2.5 text-sm font-semibold text-primary-foreground shadow-sm hover:opacity-90">
                    {{ __('Finish install') }}
                </button>
            </div>
        </form>
    @endif

    @if ($step === 5)
        <div>
            <h1 class="text-xl font-semibold text-foreground">{{ __('Installation complete') }}</h1>
            <p class="mt-2 text-sm text-muted-foreground leading-relaxed">
                {{ __('The app is ready. This installer is now disabled until storage/app/.installed is removed.') }}
            </p>
        </div>

        <div class="rounded-xl border border-border/60 bg-card/30 p-4 text-sm space-y-3">
            <p class="font-medium text-foreground">{{ __('Optional: remove installer code (recommended)') }}</p>
            <p class="text-muted-foreground">{{ __('Delete these paths, then edit bootstrap/app.php as noted in docs/CPANEL.md:') }}</p>
            <ul class="list-disc pl-5 space-y-1 font-mono text-xs text-foreground break-all">
                <li>routes/install.php</li>
                <li>app/Services/Install/</li>
                <li>app/Http/Middleware/HandleInstallationMode.php</li>
                <li>resources/views/livewire/pages/install/</li>
                <li>resources/views/layouts/install.blade.php</li>
            </ul>
            <p class="text-muted-foreground">{{ __('In bootstrap/app.php: remove the install route group (then: … routes/install.php) and remove HandleInstallationMode from the web middleware prepend list.') }}</p>
        </div>

        <a href="{{ route('login') }}" wire:navigate class="inline-flex w-full justify-center rounded-xl bg-foreground px-5 py-2.5 text-sm font-semibold text-primary-foreground shadow-sm hover:opacity-90">
            {{ __('Go to sign in') }}
        </a>
    @endif
</div>
