<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Models\Client;
use App\Models\Company;
use App\Models\CompanyFinancialSettings;
use App\Models\Plan;
use App\Models\Subscription;
use App\Models\User;
use App\Support\Demo;
use App\Support\DemoCredentials;
use Database\Seeders\DemoDataSeeder;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

/**
 * Provisiona la empresa demo compartida (flag `is_demo`) que reemplaza el
 * trial de auto-registro: una sola Company en el plan Profesional, con sus
 * 3 usuarios fijos (uno por rol), lista para el acceso vía `/demo`
 * (captura de lead + credenciales por correo, ver DemoRequestController).
 *
 * Idempotente: se puede ejecutar tantas veces como se quiera (deploy,
 * scheduler, manual) sin duplicar la Company ni los usuarios — resuelve por
 * `is_demo=true` / por email, y actualiza en lugar de crear cuando ya existen.
 */
class SetupDemoCompany extends Command
{
    protected $signature = 'credify:setup-demo {--no-seed : Provisiona la empresa/usuarios sin sembrar el dataset de ejemplo}';

    protected $description = 'Crea o actualiza la empresa demo compartida (plan Profesional + 3 usuarios por rol) y siembra datos de ejemplo si está vacía.';

    public function handle(): int
    {
        $professionalPlan = Plan::where('slug', 'professional')->first();

        if (! $professionalPlan) {
            $this->error('El plan Profesional (slug "professional") no existe. Abortando.');

            return self::FAILURE;
        }

        DB::transaction(function () use ($professionalPlan): void {
            // 1. Resolver/crear la Company demo. Se busca primero por is_demo=true
            //    (fuente de verdad tras la primera ejecución); si no existe aún,
            //    se resuelve/crea por email para no duplicarla ante una carrera.
            $company = Company::where('is_demo', true)->first()
                ?? Company::firstOrCreate(
                    ['email' => Demo::COMPANY_EMAIL],
                    ['name' => Demo::COMPANY_NAME],
                );

            $company->name = Demo::COMPANY_NAME;
            $company->status = Company::STATUS_ACTIVE;
            $company->is_demo = true;
            $company->save();

            // 2. Suscripción activa al plan Profesional, con vigencia larga (74
            //    años) para que la demo nunca caiga en grace/expired.
            Subscription::updateOrCreate(
                ['company_id' => $company->id],
                [
                    'plan_id' => $professionalPlan->id,
                    'billing_cycle' => Subscription::BILLING_ANNUAL,
                    'starts_at' => now()->startOfDay(),
                    'ends_at' => now()->addYears(74)->endOfYear(),
                    'status' => Subscription::STATUS_ACTIVE,
                    'is_active' => true,
                ],
            );

            // 3. Settings financieros por defecto (created_by_user_id es nullable,
            //    no requiere un usuario previo).
            CompanyFinancialSettings::firstOrCreate(['company_id' => $company->id]);

            // 4. Los 3 usuarios fijos, uno por rol (ver Demo::USERS). La contraseña
            //    NO se fija aquí (updateOrCreate la reescribiría en cada corrida);
            //    la fija DemoCredentials::ensure() abajo (fuera de esta transacción).
            foreach (Demo::USERS as $email => $role) {
                $user = User::firstOrNew(['email' => $email]);
                $user->name = 'Demo '.ucfirst($role);
                $user->company_id = $company->id;
                if (! $user->exists) {
                    $user->password = Str::password(24); // placeholder; ensure() lo reemplaza
                }
                $user->save();

                if (! $user->hasRole($role)) {
                    $user->syncRoles([$role]);
                }
            }
        });

        // Fija las contraseñas demo conocidas si aún no existen (no las rota en
        // cada deploy; solo credify:reset-demo rota). Ver App\Support\DemoCredentials.
        DemoCredentials::ensure();

        $this->info('Empresa demo lista: '.Demo::COMPANY_NAME.' ('.Demo::COMPANY_EMAIL.').');

        // Sembrar el dataset de ejemplo SI la demo está vacía, para que un visitante
        // nunca vea la app en ceros. Idempotente: al re-ejecutar sobre una demo ya
        // poblada (deploy/scheduler) no duplica nada — solo siembra cuando no hay
        // clientes. Los resets posteriores repueblan vía credify:reset-demo.
        // `--no-seed` omite este paso (útil en tests que controlan el seed a mano).
        $company = Company::where('is_demo', true)->first();

        if (! $this->option('no-seed') && $company && ! Client::withoutGlobalScopes()->where('company_id', $company->id)->exists()) {
            $this->info('La demo no tiene datos — sembrando dataset de ejemplo...');
            $this->call('db:seed', [
                '--class' => DemoDataSeeder::class,
                '--force' => true,
            ]);
        }

        return self::SUCCESS;
    }
}
