<?php

declare(strict_types=1);

/**
 * Evalúa la vigencia comercial de una cuenta de streaming asignada a un cliente.
 *
 * Regla de negocio:
 * - Una cuenta sin cliente asignado pertenece al inventario del Admin y no se bloquea por fecha.
 * - Una cuenta asignada puede consultarse hasta el final de su fecha de renovación, inclusive.
 * - Se considera vencida únicamente desde el día siguiente.
 */
final class AccountAccessService
{
    public function __construct(private PDO $pdo)
    {
    }

    /**
     * @return array{
     *   account_id:int,
     *   assigned:bool,
     *   accessible:bool,
     *   reason:string,
     *   renewal_date:?string,
     *   renewal_display:string,
     *   client_id:?int,
     *   client_name:string,
     *   days_remaining:?int
     * }
     */
    public function statusForAccount(int $accountId): array
    {
        if ($accountId <= 0) {
            return $this->emptyStatus($accountId, 'not_found');
        }

        $stmt = $this->pdo->prepare(
            "SELECT cs.id,
                    cs.fecha_renovacion,
                    a.id_usuario AS cliente_id,
                    u.nombre_usuario AS cliente_nombre
             FROM correos_servicios cs
             LEFT JOIN asociaciones a
                    ON a.id_correo_servicio = cs.id
                   AND a.id_admin_propietario = cs.id_admin_propietario
             LEFT JOIN usuarios u ON u.id = a.id_usuario
             WHERE cs.id = ?
             ORDER BY a.id DESC
             LIMIT 1"
        );
        $stmt->execute([$accountId]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$row) {
            return $this->emptyStatus($accountId, 'not_found');
        }

        $clientId = isset($row['cliente_id']) && $row['cliente_id'] !== null
            ? (int) $row['cliente_id']
            : null;
        $assigned = $clientId !== null && $clientId > 0;
        $renewalRaw = trim((string) ($row['fecha_renovacion'] ?? ''));

        // Inventario sin vender: la fecha sirve para control interno, no limita la consulta.
        if (!$assigned) {
            return [
                'account_id' => (int) $row['id'],
                'assigned' => false,
                'accessible' => true,
                'reason' => 'inventory',
                'renewal_date' => $renewalRaw !== '' ? $renewalRaw : null,
                'renewal_display' => $renewalRaw !== '' && strtotime($renewalRaw) !== false
                    ? date('d/m/Y', strtotime($renewalRaw))
                    : 'Sin fecha',
                'client_id' => null,
                'client_name' => '',
                'days_remaining' => null,
            ];
        }

        // Las altas nuevas exigen fecha cuando hay cliente. Para registros antiguos sin fecha,
        // se conserva el acceso y se deja constancia en el log para no cortar servicios existentes.
        if ($renewalRaw === '' || strtotime($renewalRaw) === false) {
            error_log('[AccountAccessService] Cuenta asignada sin fecha válida: ' . (int) $row['id']);
            return [
                'account_id' => (int) $row['id'],
                'assigned' => true,
                'accessible' => true,
                'reason' => 'legacy_without_date',
                'renewal_date' => null,
                'renewal_display' => 'Sin fecha',
                'client_id' => $clientId,
                'client_name' => trim((string) ($row['cliente_nombre'] ?? 'Cliente')),
                'days_remaining' => null,
            ];
        }

        $today = new DateTimeImmutable('today');
        $renewalDay = new DateTimeImmutable(date('Y-m-d', strtotime($renewalRaw)));
        $daysRemaining = (int) $today->diff($renewalDay)->format('%r%a');
        $accessible = $daysRemaining >= 0;

        return [
            'account_id' => (int) $row['id'],
            'assigned' => true,
            'accessible' => $accessible,
            'reason' => $accessible ? ($daysRemaining === 0 ? 'expires_today' : 'active') : 'expired',
            'renewal_date' => $renewalDay->format('Y-m-d'),
            'renewal_display' => $renewalDay->format('d/m/Y'),
            'client_id' => $clientId,
            'client_name' => trim((string) ($row['cliente_nombre'] ?? 'Cliente')),
            'days_remaining' => $daysRemaining,
        ];
    }

    /** @return array{account_id:int,assigned:bool,accessible:bool,reason:string,renewal_date:?string,renewal_display:string,client_id:?int,client_name:string,days_remaining:?int} */
    private function emptyStatus(int $accountId, string $reason): array
    {
        return [
            'account_id' => $accountId,
            'assigned' => false,
            'accessible' => false,
            'reason' => $reason,
            'renewal_date' => null,
            'renewal_display' => 'Sin fecha',
            'client_id' => null,
            'client_name' => '',
            'days_remaining' => null,
        ];
    }
}
