<?php

namespace App\Support;

/**
 * De una URL de YouTube o Vimeo a la plataforma y el identificador que guarda el Manager.
 *
 * **Por qué existe.** El formulario de un tutorial pide dos campos —plataforma e
 * identificador— y lo que uno tiene en la mano es **la URL del vídeo**, copiada del
 * navegador. Así que había que abrir la URL, encontrar el trozo que es el id, copiarlo sin
 * el resto y elegir la plataforma a mano. Cuatro pasos para pegar un enlace.
 *
 * Y el `videoid` es **el único campo que puede estar mal y no fallar aquí**: se guarda
 * cualquier cadena, el tutorial se sirve igual, y el vídeo no se ve en el Moodle del
 * cliente. Extraerlo de la URL quita el paso donde se cuela el error —copiar de más, o
 * copiar el `&t=120s` que YouTube pega detrás—.
 *
 * Acepta las formas que de verdad se copian del navegador:
 *
 * | Lo que se pega | Lo que sale |
 * |---|---|
 * | `https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=42s` | youtube · `dQw4w9WgXcQ` |
 * | `https://youtu.be/dQw4w9WgXcQ?si=xxx` | youtube · `dQw4w9WgXcQ` |
 * | `https://www.youtube.com/embed/dQw4w9WgXcQ` | youtube · `dQw4w9WgXcQ` |
 * | `https://www.youtube.com/shorts/dQw4w9WgXcQ` | youtube · `dQw4w9WgXcQ` |
 * | `https://vimeo.com/76979871` | vimeo · `76979871` |
 * | `https://player.vimeo.com/video/76979871` | vimeo · `76979871` |
 * | `dQw4w9WgXcQ` | el id tal cual, sin tocar la plataforma |
 */
class VideoDeTutorial
{
    /**
     * Lo que se pega, interpretado.
     *
     * Devuelve `null` en `plataforma` cuando lo pegado no es una URL reconocible: entonces
     * se trata como un identificador escrito a mano y **no se cambia la plataforma
     * elegida**, porque adivinarla ahí sería peor que no tocarla.
     *
     * @return array{plataforma:?string, id:?string}
     */
    public static function interpretar(string $pegado): array
    {
        $texto = trim($pegado);

        if ($texto === '') {
            return ['plataforma' => null, 'id' => null];
        }

        // Si no parece una URL, es un identificador escrito a mano.
        if (! preg_match('#^(https?://|//|www\.|youtu\.be|vimeo\.com|player\.vimeo\.com)#i', $texto)) {
            return ['plataforma' => null, 'id' => self::limpiar($texto)];
        }

        // ---- YouTube ----
        // `watch?v=`, `youtu.be/`, `embed/`, `shorts/` y `live/`. El id de YouTube son 11
        // caracteres de un alfabeto conocido, y acotarlo así evita arrastrar el `&t=42s`
        // o el `?si=` que el propio YouTube añade al compartir.
        $deYoutube = [
            '#[?&]v=([A-Za-z0-9_-]{11})#',
            '#youtu\.be/([A-Za-z0-9_-]{11})#',
            '#youtube\.com/(?:embed|shorts|live|v)/([A-Za-z0-9_-]{11})#',
        ];

        foreach ($deYoutube as $patron) {
            if (preg_match($patron, $texto, $coincide)) {
                return ['plataforma' => 'youtube', 'id' => $coincide[1]];
            }
        }

        // ---- Vimeo ----
        // El id es numérico. `player.vimeo.com/video/N` es la forma de incrustar, y
        // `vimeo.com/N/hash` la de los vídeos privados: el hash no se guarda porque el
        // Manager solo maneja el id.
        if (preg_match('#(?:player\.)?vimeo\.com/(?:video/)?(\d{6,})#', $texto, $coincide)) {
            return ['plataforma' => 'vimeo', 'id' => $coincide[1]];
        }

        // Es una URL, pero no de una de las dos plataformas: no se inventa nada.
        return ['plataforma' => null, 'id' => null];
    }

    /**
     * La URL para ver el vídeo, que es la que se copia.
     *
     * La misma que calcula la API en `video_url`, para que copiar de aquí y lo que recibe
     * el cliente sean el mismo enlace.
     */
    public static function url(?string $plataforma, ?string $id): ?string
    {
        if ($id === null || trim($id) === '') {
            return null;
        }

        return match ($plataforma) {
            'vimeo' => 'https://vimeo.com/' . $id,
            'youtube' => 'https://www.youtube.com/watch?v=' . $id,
            default => null,
        };
    }

    /**
     * Si el identificador tiene la forma que esa plataforma usa.
     *
     * No comprueba que el vídeo exista —eso exige salir a internet— pero sí que no sea un
     * pegote: un id de YouTube de 30 caracteres o un Vimeo con letras **no van a
     * funcionar** en el Moodle del cliente, y hoy se guardan sin decir nada.
     */
    public static function pareceValido(?string $plataforma, ?string $id): bool
    {
        $id = trim((string) $id);

        if ($id === '') {
            return false;
        }

        return match ($plataforma) {
            'youtube' => (bool) preg_match('/^[A-Za-z0-9_-]{11}$/', $id),
            'vimeo' => (bool) preg_match('/^\d{6,}$/', $id),
            default => false,
        };
    }

    /** Quita lo que se cuela al copiar: espacios, comillas y parámetros pegados detrás. */
    private static function limpiar(string $texto): string
    {
        $texto = trim($texto, " \t\n\r\0\x0B\"'<>");

        // Un id con `&` o `?` detrás es un copiado de más.
        return preg_replace('/[?&#].*$/', '', $texto) ?? $texto;
    }
}
