<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;

class GraduateVideo extends Model
{
    protected $table = 'graduate_videos';

    protected $fillable = [
        'title',
        'slug',
        'description',
        'duration_seconds',
        'thumbnail_path',
        'video_url',
        'stored_video_path',
        'sort_order',
        'enabled',
    ];

    protected $casts = [
        'enabled' => 'boolean',
        'sort_order' => 'integer',
        'duration_seconds' => 'integer',
    ];

    protected static function boot()
    {
        parent::boot();

        static::saving(function (GraduateVideo $video) {
            if (! static::slugColumnExists()) {
                return;
            }

            $slug = trim((string) $video->slug);
            if ($slug === '') {
                $slug = Str::slug($video->title) ?: 'video';
            }
            $video->slug = static::ensureUniqueSlug($slug, $video->getKey());
        });
    }

    /**
     * يعود false قبل تشغيل هجرة الأعمدة الجديدة — لتجنب استعلامات عن عمود غير موجود.
     * لا نستخدم كاشاً ثابتاً حتى يُكتشف العمود بعد تشغيل migrate في نفس بيئة التشغيل.
     */
    public static function slugColumnExists(): bool
    {
        try {
            return Schema::hasColumn((new static)->getTable(), 'slug');
        } catch (\Throwable $e) {
            return false;
        }
    }

    /**
     * أسماء الأعمدة الحالية في الجدول (للسيرفرات التي لم تُشغِّل بعد كل هجرات graduate_videos).
     *
     * @return array<int, string>
     */
    public static function databaseColumnListing(): array
    {
        try {
            return Schema::getColumnListing((new static)->getTable());
        } catch (\Throwable $e) {
            return [];
        }
    }

    public static function hasDatabaseColumn(string $column): bool
    {
        return in_array($column, static::databaseColumnListing(), true);
    }

    /**
     * يُسقط أي حقول غير موجودة كأعمدة حتى لا يفشل INSERT/UPDATE قبل تشغيل الهجرة.
     *
     * @param  array<string, mixed>  $attributes
     * @return array<string, mixed>
     */
    public static function onlyExistingColumns(array $attributes): array
    {
        $allowed = array_flip(static::databaseColumnListing());
        $out = [];
        foreach ($attributes as $key => $value) {
            if (isset($allowed[$key])) {
                $out[$key] = $value;
            }
        }

        return $out;
    }

    /**
     * @param  int|string|null  $exceptId
     */
    public static function ensureUniqueSlug(string $base, $exceptId = null): string
    {
        $slug = $base !== '' ? $base : 'video';
        $candidate = $slug;
        $n = 1;

        while (
            static::slugColumnExists()
            && static::query()
                ->where('slug', $candidate)
                ->when(! is_null($exceptId), function ($q) use ($exceptId) {
                    $q->where('id', '!=', $exceptId);
                })
                ->exists()
        ) {
            $candidate = $slug.'-'.$n++;
        }

        return $candidate;
    }

    public function getRouteKeyName(): string
    {
        return static::slugColumnExists() ? 'slug' : 'id';
    }

    /**
     * قيمة {graduate_video} عند توليد الرابط — slug أو معرف السجل إذا لم يُجرَ الهجرة بعد.
     */
    public function getRouteKey()
    {
        if (! static::slugColumnExists()) {
            return (string) $this->getAttribute('id');
        }

        $slug = $this->getAttribute('slug');
        if (! empty($slug)) {
            return $slug;
        }

        return (string) $this->getAttribute('id');
    }

    /**
     * دعم الربط بـ slug أو بالمعرف الرقمي (fallback).
     *
     * @param  mixed  $value
     * @param  string|null  $field
     * @return \Illuminate\Database\Eloquent\Model|null
     */
    public function resolveRouteBinding($value, $field = null)
    {
        if (! static::slugColumnExists()) {
            return static::where('id', $value)->firstOrFail();
        }

        $field = $field ?: $this->getRouteKeyName();

        if ($field === 'slug') {
            return static::query()
                ->where(function ($q) use ($value) {
                    $q->where('slug', $value);
                    if ($value !== null && $value !== '' && ctype_digit((string) $value)) {
                        $q->orWhere('id', (int) $value);
                    }
                })
                ->firstOrFail();
        }

        return parent::resolveRouteBinding($value, $field);
    }

    public function scopeActive($query)
    {
        return $query->where('enabled', true);
    }

    public function hasStoredVideo(): bool
    {
        return ! empty($this->stored_video_path);
    }

    public function storedVideoAssetUrl(): ?string
    {
        if (! $this->hasStoredVideo()) {
            return null;
        }

        return asset($this->stored_video_path);
    }

    public function youtubeVideoId(): ?string
    {
        if ($this->hasStoredVideo()) {
            return null;
        }

        return self::parseYoutubeIdFromUrl((string) $this->video_url);
    }

    public function vimeoVideoId(): ?string
    {
        if ($this->hasStoredVideo()) {
            return null;
        }

        return self::parseVimeoIdFromUrl((string) $this->video_url);
    }

    /**
     * Absolute URL for card thumbnail, or null (UI shows gradient placeholder).
     */
    public function thumbnailUrl(): ?string
    {
        if (! empty($this->thumbnail_path)) {
            return asset($this->thumbnail_path);
        }

        $yt = $this->youtubeVideoId();
        if ($yt !== null) {
            return 'https://img.youtube.com/vi/'.$yt.'/hqdefault.jpg';
        }

        return null;
    }

    public function durationFormatted(): ?string
    {
        $sec = $this->duration_seconds;
        if ($sec === null || $sec < 1) {
            return null;
        }

        $h = intdiv($sec, 3600);
        $m = intdiv($sec % 3600, 60);
        $s = $sec % 60;

        if ($h > 0) {
            return sprintf('%d:%02d:%02d', $h, $m, $s);
        }

        return sprintf('%d:%02d', $m, $s);
    }

    /**
     * Build an iframe-safe embed URL from a pasted YouTube/Vimeo (or direct embed) link.
     */
    public function resolvedEmbedUrl(): ?string
    {
        if ($this->hasStoredVideo()) {
            return null;
        }

        $url = trim((string) $this->video_url);
        if ($url === '') {
            return null;
        }

        $yt = self::parseYoutubeIdFromUrl($url);
        if ($yt !== null) {
            return 'https://www.youtube.com/embed/'.$yt;
        }

        $vm = self::parseVimeoIdFromUrl($url);
        if ($vm !== null) {
            return 'https://player.vimeo.com/video/'.$vm;
        }

        if (Str::startsWith($url, ['http://', 'https://'])) {
            return $url;
        }

        return null;
    }

    public static function parseYoutubeIdFromUrl(string $url): ?string
    {
        $url = trim($url);
        if ($url === '') {
            return null;
        }

        if (preg_match('/youtube\.com\/embed\/([a-zA-Z0-9_-]+)/', $url, $m)) {
            return $m[1];
        }
        if (preg_match('/youtube\.com\/shorts\/([a-zA-Z0-9_-]+)/', $url, $m)) {
            return $m[1];
        }
        if (preg_match('/[?&]v=([a-zA-Z0-9_-]{11})/', $url, $m)) {
            return $m[1];
        }
        if (preg_match('/youtu\.be\/([a-zA-Z0-9_-]+)/', $url, $m)) {
            return $m[1];
        }

        return null;
    }

    public static function parseVimeoIdFromUrl(string $url): ?string
    {
        $url = trim($url);
        if ($url === '') {
            return null;
        }

        if (preg_match('/vimeo\.com\/(?:video\/)?(\d+)/', $url, $m)) {
            return $m[1];
        }

        return null;
    }

    /**
     * Parse duration from admin input: seconds integer or "mm:ss" / "h:mm:ss".
     */
    public static function parseDurationInput(?string $input): ?int
    {
        $input = trim((string) $input);
        if ($input === '') {
            return null;
        }

        if (preg_match('/^\d+$/', $input)) {
            return max(1, (int) $input);
        }

        $parts = array_map('intval', explode(':', $input));
        if (count($parts) === 2) {
            return max(1, $parts[0] * 60 + $parts[1]);
        }
        if (count($parts) === 3) {
            return max(1, $parts[0] * 3600 + $parts[1] * 60 + $parts[2]);
        }

        return null;
    }
}
