<?php

namespace App\Livewire\Admin;

use App\Models\Host;
use App\Models\ProvisioningRun;
use App\Provisioning\Jobs\AdvanceRunJob;
use Illuminate\Support\Collection;
use Livewire\Attributes\Layout;
use Livewire\Attributes\On;
use Livewire\Component;

#[Layout('layouts.admin')]
class HostDetail extends Component
{
    public Host $host;

    public function mount(Host $host): void
    {
        $this->host = $host;
    }

    /** Live refresh whenever any run advances (admins-only channel). */
    #[On('echo-private:admin.runs,StepAdvanced')]
    public function onStepAdvanced(): void
    {
        $this->host->refresh();
    }

    /** Adjust the capacity reserve (% of storage kept free for headroom). */
    public function saveReserve(int $reserve): void
    {
        $this->authorize('hosts.manage');
        $reserve = max(0, min(90, $reserve));
        $this->host->update(['reserve_pct' => $reserve]);
        $this->dispatch('notify', message: __('hosts.detail.reserve_saved'));
    }

    /**
     * Drain / return a host: toggle between active and disabled. Disabled takes
     * it out of placement (maintenance) without purging it — distinct from the
     * destructive "remove host". Never touches a host mid-onboarding.
     */
    public function toggleMaintenance(): void
    {
        $this->authorize('hosts.manage');
        if ($this->host->status === 'active') {
            $this->host->update(['status' => 'disabled']);
        } elseif ($this->host->status === 'disabled') {
            $this->host->update(['status' => 'active']);
        }
    }

    public function retry(): void
    {
        $this->authorize('hosts.manage');
        $run = $this->currentRun();

        if ($run !== null && $run->status === ProvisioningRun::STATUS_FAILED) {
            $run->update([
                'status' => ProvisioningRun::STATUS_RUNNING,
                'attempt' => 0,
                'next_attempt_at' => now(),
                'started_at' => now(), // reset the step timer so it doesn't re-time-out instantly
                'error' => null,
            ]);
            $this->host->update(['status' => 'onboarding']);
            AdvanceRunJob::dispatch($run->uuid);
        }
    }

    private function currentRun(): ?ProvisioningRun
    {
        return $this->host->runs()->latest('id')->first();
    }

    /** @return array<int, array{label: string, state: string}> */
    private function buildSteps(?ProvisioningRun $run): array
    {
        $pipeline = config('provisioning.pipelines.host', []);
        $current = $run?->current_step ?? 0;
        $status = $run?->status;

        $steps = [];
        foreach ($pipeline as $index => $class) {
            if ($status === ProvisioningRun::STATUS_COMPLETED || $index < $current) {
                $state = 'done';
            } elseif ($index === $current) {
                $state = $status === ProvisioningRun::STATUS_FAILED ? 'failed' : 'running';
            } else {
                $state = 'pending';
            }

            $steps[] = ['label' => __(app($class)->label()), 'state' => $state];
        }

        return $steps;
    }

    public function render()
    {
        $run = $this->currentRun();

        /** @var Collection $events */
        $events = $run
            ? $run->events()->latest('id')->limit(30)->get()
            : collect();

        return view('livewire.admin.host-detail', [
            'run' => $run,
            'steps' => $this->buildSteps($run),
            'events' => $events,
            'instances' => $this->host->instances()->latest('id')->get(),
            'health' => $this->host->healthState(),
        ]);
    }
}
