<?php

namespace App\Livewire\Clients;

use App\Models\Clients\Client;
use Livewire\Component;

class Show extends Component
{
    public Client $client;

    public function mount(Client $client)
    {
        $this->client = $client;
        $this->cargar();
    }

    /**
     * Todo lo que pinta la ficha, en una carga.
     *
     * `licenseToken.products` y `type` de cada entorno se precargan porque la ficha
     * lista los entornos: sin esto, cada fila haría sus propias consultas.
     */
    private function cargar(): void
    {
        $this->client->load([
            'tokens.products',
            'environments.type',
            'deactivatedBy',
        ]);
    }

    /**
     * Los productos que recibe el cliente, sin repetir.
     *
     * Salen de sus licencias, así que un cliente sin licencias no tiene productos. Se
     * calculan desde las licencias ya cargadas y no con otra consulta.
     *
     * @return \Illuminate\Support\Collection
     */
    public function productos()
    {
        return $this->client->tokens
            ->flatMap->products
            ->unique('id')
            ->sortBy('name')
            ->values();
    }

    /**
     * Los contactos, listos para pintar.
     *
     * El JSON de `contacts` guarda `name`, `email` y `phone` —**no hay cargo**, aunque
     * el diseño lo dibujaba: se pinta solo si algún día existe—. Las iniciales se
     * calculan aquí para no meter lógica en la vista.
     *
     * @return array<int, array<string, string|null>>
     */
    public function contactos(): array
    {
        return collect($this->client->contacts ?? [])
            ->map(function ($contacto) {
                $nombre = trim((string) ($contacto['name'] ?? ''));

                return [
                    'nombre' => $nombre !== '' ? $nombre : 'Sin nombre',
                    'cargo' => $contacto['position'] ?? $contacto['cargo'] ?? null,
                    'email' => $contacto['email'] ?? null,
                    'telefono' => $contacto['phone'] ?? null,
                    'iniciales' => $this->iniciales($nombre),
                ];
            })
            ->all();
    }

    private function iniciales(string $nombre): string
    {
        $palabras = preg_split('/\s+/', trim($nombre), -1, PREG_SPLIT_NO_EMPTY) ?: [];

        if ($palabras === []) {
            return '?';
        }

        return collect($palabras)
            ->take(2)
            ->map(fn ($palabra) => mb_strtoupper(mb_substr($palabra, 0, 1)))
            ->implode('');
    }

    /**
     * Los entornos del cliente con su estado de sincronización.
     *
     * **Tres estados, no dos**, igual que en el listado de Entornos: nunca sincronizado
     * es un alta sin terminar y sin señal es una avería. Mezclarlos manda a Sistemas a
     * mirar un servidor que nunca se conectó.
     *
     * @return array<int, array<string, mixed>>
     */
    public function entornos(): array
    {
        return $this->client->environments
            ->sortBy('domain')
            ->map(function ($entorno) {
                $sincronizado = $entorno->refresh_at !== null;
                $dias = $sincronizado
                    ? $entorno->refresh_at->copy()->startOfDay()->diffInDays(now()->startOfDay())
                    : null;

                return [
                    'id' => $entorno->id,
                    'nombre' => $entorno->name,
                    'dominio' => $entorno->domain,
                    'env' => $entorno->env,
                    'version' => $entorno->version,
                    'tipo' => $entorno->type?->name,
                    'nunca' => ! $sincronizado,
                    // Mismo umbral que el Dashboard y que el listado de Entornos.
                    'sinSenal' => $sincronizado && $dias >= 3,
                    'dias' => $dias,
                    'fecha' => $entorno->refresh_at?->diffForHumans(),
                ];
            })
            ->all();
    }

    /**
     * Cuántos entornos están sin señal y cuántos sin sincronizar.
     *
     * @return array{sinSenal:int, sinSincronizar:int, total:int}
     */
    public function resumenDeEntornos(): array
    {
        $entornos = collect($this->entornos());

        return [
            'total' => $entornos->count(),
            'sinSenal' => $entornos->where('sinSenal', true)->count(),
            'sinSincronizar' => $entornos->where('nunca', true)->count(),
        ];
    }

    /**
     * Abre la baja o el alta del cliente.
     *
     * Va aparte del formulario a propósito: dos caminos al mismo estado, uno con
     * consecuencias y otro silencioso, hace que se use el silencioso.
     */
    public function abrirCambioDeEstado(): void
    {
        $this->authorize('admin.clients.edit');

        $this->dispatch('openModal',
            component: \App\Livewire\Clients\ClientStatusModal::class,
            arguments: ['clientId' => $this->client->id]
        );
    }

    #[\Livewire\Attributes\On('clientStatusChanged')]
    public function refrescarCliente(): void
    {
        $this->client->refresh();
        $this->cargar();
    }

    public function render()
    {
        return view('livewire.clients.show', [
            'client' => $this->client,
            'productos' => $this->productos(),
            'contactos' => $this->contactos(),
            'entornos' => $this->entornos(),
            'resumenDeEntornos' => $this->resumenDeEntornos(),
            'impacto' => $this->client->actived
                ? $this->client->impactoDeLaBaja()
                : $this->client->impactoDelAlta(),
        ])->layout('layouts.app');
    }
}
