<?php

namespace Database\Seeders;

use App\Models\Customer;
use App\Models\Datacenter;
use App\Models\Host;
use App\Models\Instance;
use App\Models\Operator;
use App\Models\Order;
use App\Models\ProvisioningRun;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        // Never create a known-credential account outside local/testing.
        if (! app()->environment('local', 'testing')) {
            return;
        }

        $operator = Operator::updateOrCreate(
            ['email' => env('SEED_ADMIN_EMAIL', 'admin@clupilot.local')],
            [
                'name' => 'Admin',
                'password' => Hash::make(env('SEED_ADMIN_PASSWORD', 'password')),
            ],
        );
        if (! $operator->hasRole('Owner')) {
            $operator->assignRole('Owner');
        }

        // A plain customer to exercise the portal (and prove the admin gate).
        // Never is_admin: that flag is dead, and the console account above is
        // not a `users` row at all any more.
        User::updateOrCreate(
            ['email' => 'kunde@clupilot.local'],
            [
                'name' => 'Dr. S. Berger',
                'password' => Hash::make(env('SEED_ADMIN_PASSWORD', 'password')),
            ],
        );

        // Datacenters — hosts + orders pick their code.
        foreach ([['fsn', 'Falkenstein', 'DE'], ['hel', 'Helsinki', 'FI']] as [$dcCode, $dcName, $dcLocation]) {
            $datacenter = Datacenter::updateOrCreate(
                ['code' => $dcCode],
                ['name' => $dcName, 'location' => $dcLocation, 'active' => true],
            );

            // next_host_number gehört NICHT ins zweite Argument von
            // updateOrCreate(): das schriebe bei jedem erneuten Säen auf 2
            // zurück, auch auf einer Installation, die längst weiterzählt —
            // genau die Wiederverwendung, gegen die dieser ganze Umbau
            // gebaut wurde. max() hält stattdessen den höheren der beiden
            // Werte: frisch angelegt steht die Spalte auf ihrem
            // Schema-Default 1, max(1, 2) hebt sie auf 2 (die 01 ist unten
            // durch die Demoflotte belegt); bestand die Zeile schon und
            // zählte höher, bleibt sie stehen.
            $datacenter->update(['next_host_number' => max($datacenter->next_host_number, 2)]);
        }

        // Demo fleet so the operator console hosts view has content locally.
        // Namen wie die Konsole sie selbst vergäbe (App\Support\HostName) —
        // seit der Hostnamen-Vergabe ist ein getippter `pve-…`-Name genau das
        // Gegenbeispiel zu der Regel, die diese Installation gerade lernt.
        $fleet = [
            ['name' => 'fsn-01', 'datacenter' => 'fsn', 'public_ip' => '203.0.113.11', 'wg_ip' => '10.66.0.2'],
            ['name' => 'hel-01', 'datacenter' => 'hel', 'public_ip' => '203.0.113.21', 'wg_ip' => '10.66.0.3'],
        ];
        foreach ($fleet as $host) {
            Host::updateOrCreate(['name' => $host['name']], [
                'datacenter' => $host['datacenter'],
                'public_ip' => $host['public_ip'],
                'wg_ip' => $host['wg_ip'],
                'status' => 'active',
                'total_gb' => 2000,
                'total_ram_mb' => 131072,
                'cpu_cores' => 32,
                'cpu_weight' => 32,
                'reserve_pct' => 15,
                'pve_version' => 'pve-manager/8.2.2',
                'node' => $host['name'],
                'last_seen_at' => now(),
            ]);
        }

        // A live customer (matched to the portal login) with an active instance.
        $fsn1 = Host::query()->where('name', 'fsn-01')->first();
        $berger = Customer::updateOrCreate(
            ['email' => 'kunde@clupilot.local'],
            ['name' => 'Kanzlei Berger', 'locale' => 'de'],
        );
        $berger->ensureUser(); // links to the kunde@clupilot.local portal login (admin impersonation)
        $bergerOrder = Order::updateOrCreate(
            ['stripe_event_id' => 'seed_berger'],
            // 7900 = 79,00 €, der Team-Monatspreis auf der neuen Leiter.
            ['customer_id' => $berger->id, 'plan' => 'team', 'amount_cents' => 7900, 'currency' => 'EUR', 'datacenter' => 'fsn', 'status' => 'active'],
        );
        Instance::updateOrCreate(
            ['subdomain' => 'kanzlei-berger'],
            [
                'customer_id' => $berger->id, 'order_id' => $bergerOrder->id, 'host_id' => $fsn1?->id,
                'vmid' => 101, 'plan' => 'team', 'quota_gb' => 500, 'disk_gb' => 540, 'ram_mb' => 8192,
                'cores' => 4, 'status' => 'active', 'cert_ok' => true, 'route_written' => true,
            ],
        );

        // A few in-flight runs so the operator provisioning console has content.
        $demoRuns = [
            ['name' => 'Ordination Dr. Fux', 'plan' => 'start', 'step' => 7, 'status' => 'running'],
            ['name' => 'Weingut Prantl', 'plan' => 'business', 'step' => 13, 'status' => 'waiting'],
            ['name' => 'Praxis Sommer', 'plan' => 'team', 'step' => 2, 'status' => 'failed'],
        ];
        foreach ($demoRuns as $i => $demo) {
            $customer = Customer::updateOrCreate(
                ['email' => "demo{$i}@clupilot.local"],
                ['name' => $demo['name'], 'locale' => 'de'],
            );
            $customer->ensureUser(); // portal login so the admin can impersonate
            $order = Order::updateOrCreate(
                ['stripe_event_id' => "seed_demo_{$i}"],
                ['customer_id' => $customer->id, 'plan' => $demo['plan'], 'amount_cents' => 1900, 'currency' => 'EUR', 'datacenter' => 'fsn', 'status' => 'provisioning'],
            );
            ProvisioningRun::updateOrCreate(
                ['subject_type' => Order::class, 'subject_id' => $order->id, 'pipeline' => 'customer'],
                ['current_step' => $demo['step'], 'status' => $demo['status'], 'attempt' => $demo['status'] === 'failed' ? 3 : 1, 'context' => []],
            );
        }
    }
}
