<?php

namespace App\Http\Controllers;

use App\Models\Video;
use Illuminate\Http\Request;
use App\Http\Requests\CreateVideoRequest;
use App\Http\Requests\UpdateVideoRequest;
use Illuminate\Support\Facades\Storage;
use App\Models\Category;

class VideosController extends Controller
{
    public function __construct()
    {
        // Aumentar limites temporariamente para uploads grandes
        // Nota: Estas configurações devem ser feitas antes do PHP processar o POST
        // Por isso também estão no public/index.php
        @ini_set('upload_max_filesize', '200M');
        @ini_set('post_max_size', '200M');
        @ini_set('max_execution_time', '300'); // 5 minutos
        @ini_set('max_input_time', '300');
        @ini_set('memory_limit', '512M');
    }

    public function index(Request $request)
    {
        $user = auth()->user();

        if (!$user) {
            return response()->json([
                'message' => 'Utilizador não autenticado',
                'data' => null,
            ], 401);
        }

        $userId = $user->id;
        $role = $user->role_id;
        $userSector = $user->sector_id;

        $search = trim((string) $request->query('search', ''));
        $categoryId = $request->query('category');
        $watched = $request->query('watched');
        $status = $request->query('status');
        $perPage = $request->query('per_page', 9);

        $query = Video::select(['id', 'title', 'thumbnail', 'is_active'])
            ->with('categories:id,name')
            ->with('sectors:id')

            ->when($search !== '', function ($q) use ($search) {
                $q->where(function ($sub) use ($search) {
                    $sub->where('title', 'like', "%{$search}%")
                        ->orWhere('tags', 'like', "%{$search}%");
                });
            })

            ->when($categoryId, function ($q) use ($categoryId) {
                $q->whereHas('categories', function ($c) use ($categoryId) {
                    $c->where('categories.id', $categoryId);
                });
            })

            ->when($role !== 1, fn($q) => $q->where('is_active', true))

            ->when($role !== 1, fn($q) => $q->whereHas('sectors', function ($s) use ($userSector) {
                $s->where('sectors.id', $userSector)
                  ->orWhere('sectors.slug', "global");
            }))

            ->when(
                $role === 1 && $status === 'active',
                fn($q) =>
                $q->where('is_active', true)
            )

            ->when(
                $role === 1 && $status === 'inactive',
                fn($q) =>
                $q->where('is_active', false)
            )

            ->when($watched !== null, function ($q) use ($watched, $userId) {
                (int) $watched === 1
                    ? $q->whereHas('views', fn($v) => $v->where('user_id', $userId))
                    : $q->whereDoesntHave('views', fn($v) => $v->where('user_id', $userId));
            })

            // left join para trazer os vídeos vistos pelo utilizador 
            ->leftJoin('video_views as vv', function ($join) use ($userId) {
                $join->on('vv.video_id', '=', 'videos.id')
                    ->where('vv.user_id', '=', $userId);
            })

            ->orderByRaw('CASE WHEN vv.id IS NOT NULL THEN 1 ELSE 0 END ASC')
            ->orderBy('videos.order', 'ASC')
            ->select(['videos.id', 'videos.title', 'videos.thumbnail', 'videos.is_active', 'vv.id as user_view_id'])

            ->paginate($perPage);

        // 1 única query para obter o número de vídeos ativos e vistos
        if ($role !== 1) {
            $stats = Video::query()
                ->where('is_active', true)
                ->whereHas('sectors', function ($s) use ($userSector) {
                    $s->where('sectors.id', $userSector)
                      ->orWhere('sectors.slug', "global");
                })
                ->selectRaw('
                    COUNT(*) as active_count,
                    COUNT(CASE WHEN EXISTS (
                        SELECT 1 FROM video_views
                        WHERE video_views.video_id = videos.id
                        AND video_views.user_id = ?
                    ) THEN 1 END) as watched_count
                ', [$userId])
                ->first();
        } else {
            $stats = Video::selectRaw('
                COUNT(CASE WHEN is_active = 1 THEN 1 END) as active_count,
                COUNT(CASE WHEN is_active = 1 AND EXISTS (
                    SELECT 1 FROM video_views
                    WHERE video_views.video_id = videos.id
                    AND video_views.user_id = ?
                ) THEN 1 END) as watched_count
            ', [$userId])
                ->first();
        }

        $query->getCollection()->transform(function ($video) {
            return [
                'id' => $video->id,
                'title' => $video->title,
                'thumbnail' => $video->thumbnail,
                'is_active' => $video->is_active,
                'categories' => $video->categories,
                'watched' => $video->user_view_id !== null,
            ];
        });

        // Guarda as categorias em cache durante 1 minuto para evitar consultas repetidas
        if ($role !== 1) {
            $categories = cache()->remember(
                'active_categories_with_videos',
                60,
                fn() =>
                Category::select('id', 'name')
                    ->where('is_active', true)
                    ->whereHas('videos')
                    ->whereHas('videos.sectors', function ($s) use ($userSector) {
                        $s->where('sectors.id', $userSector)
                          ->orWhere('sectors.slug', "global");
                    })
                    ->orderBy('name')
                    ->get()
            );
        } else {
            $categories = cache()->remember(
                'active_categories_with_videos_admin',
                60,
                fn() =>
                Category::select('id', 'name')
                    ->where('is_active', true)
                    ->whereHas('videos')
                    ->orderBy('name')
                    ->get()
            );
        }

        return response()->json([
            'message' => 'Vídeos obtidos com sucesso',
            'data' => $query->items(),
            'meta' => [
                'current_page' => $query->currentPage(),
                'last_page' => $query->lastPage(),
                'per_page' => $query->perPage(),
                'total' => $query->total(),
            ],
            'userId' => $userId,
            'role' => $role,
            'categories' => $categories,
            'videosActive' => $stats->active_count,
            'videosWatched' => $stats->watched_count ?? 0,
        ]);
    }

    public function search(Request $request)
    {
        $user = auth()->user();
        $userSector = $user->sector_id;

        $search = trim((string) $request->query('search', ''));

        $videos = Video::select(['id', 'title', 'thumbnail', 'is_active'])
            ->with([
                'categories:id,name',
                'views' => function ($query) use ($user) {
                    $query->select('id', 'video_id', 'user_id')
                        ->where('user_id', $user->id);
                }
            ])
            ->when($user->role_id !== 1, function ($query) use ($userSector) {
                $query->where('is_active', true)
                    ->whereHas('sectors', function ($s) use ($userSector) {
                        $s->where('sectors.id', $userSector)
                          ->orWhere('sectors.slug', "global");
                    });
            })
            ->where(function ($query) use ($search) {
                $query->where('title', 'like', "%{$search}%")
                    ->orWhere('tags', 'like', "%{$search}%");
            })
            ->limit(20)
            ->get()
            ->map(function ($video) {
                return [
                    'id' => $video->id,
                    'title' => $video->title,
                    'thumbnail' => $video->thumbnail,
                    'is_active' => $video->is_active,
                    'categories' => $video->categories,
                    'watched' => $video->views->isNotEmpty(),
                ];
            });

        return response()->json([
            'message' => 'Resultados obtidos com sucesso',
            'data' => $videos,
        ]);
    }

    public function getVideo($id)
    {
        $user = auth()->user();

        if (!$user) {
            return response()->json([
                'message' => 'Utilizador não autenticado',
                'data' => null,
                'errors' => null,
            ], 404);
        }

        $userID = $user->id;
        $userSector = $user->sector_id;
        $isAdmin = $user->role_id === 1;

        $video = Video::with([
            'categories' => function ($query) use ($isAdmin) {
                if (!$isAdmin) {
                    $query->where('is_active', true);
                }
            },
            'sectors',
            'views' => function ($query) use ($userID) {
                $query->where('user_id', $userID);
            },
        ])->find($id);

        if (!$video) {
            return response()->json([
                'message' => 'Vídeo não encontrado',
                'data' => null,
                'errors' => null,
            ], 404);
        }

        if (!$isAdmin) {
            if (!$video->is_active) {
                return response()->json([
                    'message' => 'Acesso negado',
                    'data' => null,
                    'errors' => null,
                ], 404);
            }

            if (!$video->sectors->contains(fn ($sector) => $sector->id === $userSector || $sector->slug === 'global')) {
                return response()->json([
                    'message' => 'Acesso negado',
                    'data' => null,
                    'errors' => null,
                ], 404);
            }

            $nextVideo = Video::select('id')
                ->where('order', '>', $video->order)
                ->where('is_active', true)
                ->whereHas('sectors', fn($s) => $s->where('sectors.id', $userSector)
                    ->orWhere('sectors.slug', "global"))
                ->orderBy('order', 'asc')
                ->first();

            $previousVideo = Video::select('id')
                ->where('order', '<', $video->order)
                ->where('is_active', true)
                ->whereHas('sectors', fn($s) => $s->where('sectors.id', $userSector)
                    ->orWhere('sectors.slug', "global"))
                ->orderBy('order', 'desc')
                ->first();
        } else {
            $nextVideo = Video::select('id')
                ->where('order', '>', $video->order)
                ->orderBy('order', 'asc')
                ->first();

            $previousVideo = Video::select('id')
                ->where('order', '<', $video->order)
                ->orderBy('order', 'desc')
                ->first();
        }

        $video->url = Storage::url($video->url);
        $video->thumbnail = Storage::url($video->thumbnail);

        return response()->json([
            'message' => 'Vídeo obtido com sucesso',
            'data' => [
                'id' => $video->id,
                'title' => $video->title,
                'description' => $video->description,
                'url' => $video->url,
                'thumbnail' => $video->thumbnail,
                'duration' => $video->duration,
                'tags' => $video->tags,
                'order' => $video->order,
                'categories' => $video->categories->map(function ($category) {
                    return [
                        'id' => $category->id,
                        'name' => $category->name,
                    ];
                })->values(),
                'sectors' => $video->sectors->map(function ($sector) {
                    return [
                        'id' => $sector->id,
                        'name' => $sector->name,
                    ];
                })->values(),
                'is_active' => $video->is_active,
                'watched' => $video->views->isNotEmpty(),
            ],
            'errors' => null,
            'nextVideo' => $nextVideo->id ?? null,
            'previousVideo' => $previousVideo->id ?? null,
        ], 200);
    }


    public function create(CreateVideoRequest $request)
    {
        $user = auth()->user();

        if (!$user) {
            return response()->json([
                'message' => 'Utilizador não autenticado',
                'data' => null,
                'errors' => null,
            ], 404);
        }

        $validated = $request->validated();

        $videoPath = $request->file('url')->store('videos', 'public');
        $thumbnailPath = $request->file('thumbnail')->store('thumbnails', 'public');

        $video = Video::create([
            'title' => $validated['title'],
            'description' => $validated['description'],
            'url' => $videoPath,
            'thumbnail' => $thumbnailPath,
            'duration' => $validated['duration'] ?? '00:00',
            'tags' => $validated['tags'],
            'order' => $validated['order'],
        ]);

        $video->categories()->sync($request->input('category_ids', []));
        $video->sectors()->sync($request->input('sector_ids', []));

        $baseUrl = $request->getSchemeAndHttpHost();

        return response()->json([
            'message' => 'Vídeo adicionado com sucesso',
            'data' => [
                'id' => $video->id,
                'title' => $video->title,
                'description' => $video->description,
                'url' => $baseUrl . Storage::url($video->url),
                'thumbnail' => $baseUrl . Storage::url($video->thumbnail),
                'duration' => $video->duration,
                'tags' => $video->tags,
                'order' => $video->order,
                'categories' => $video->categories->pluck('name'),
                'sectors' => $video->sectors->pluck('name'),
                'is_active' => $video->is_active,
            ],
            'errors' => null,
        ], 201);
    }

    public function update(UpdateVideoRequest $request, $id)
    {
        $user = auth()->user();

        if (!$user) {
            return response()->json([
                'message' => 'Utilizador não autenticado',
                'data' => null,
                'errors' => null,
            ], 404);
        }

        $videoToUpdate = Video::find($id);

        if (!$videoToUpdate) {
            return response()->json([
                'message' => 'Vídeo não encontrado',
                'data' => null,
                'errors' => null,
            ], 404);
        }

        $validated = $request->validated();

        if ($request->hasFile('thumbnail')) {
            // Apagar thumbnail antiga
            if ($videoToUpdate->thumbnail && Storage::disk('public')->exists($videoToUpdate->thumbnail)) {
                Storage::disk('public')->delete($videoToUpdate->thumbnail);
            }
            $validated['thumbnail'] = $request->file('thumbnail')->store('thumbnails', 'public');
        }

        try {

            $videoToUpdate->update([
                'title' => $validated['title'] ?? $videoToUpdate->title,
                'description' => $validated['description'] ?? $videoToUpdate->description,
                'tags' => $validated['tags'] ?? $videoToUpdate->tags,
                'thumbnail' => $validated['thumbnail'] ?? $videoToUpdate->thumbnail,
                'is_active' => array_key_exists('is_active', $validated) ? $validated['is_active'] : $videoToUpdate->is_active,
                'order' => $validated['order'] ?? $videoToUpdate->order,
            ]);

            $videoToUpdate->categories()->sync($request->input('category_ids', []));
            $videoToUpdate->sectors()->sync($request->input('sector_ids', []));

            return response()->json([
                'message' => 'Dados do vídeo atualizados com sucesso',
                'data' => $videoToUpdate->load(['categories', 'sectors']),
                'errors' => null,
            ], 200);
        } catch (\Throwable $th) {
            return response()->json([
                'message' => 'Não foi possível atualizar o vídeo',
                'data' => null,
                'errors' => null,
            ], 500);
        }
    }

    public function destroy($id)
    {
        $user = auth()->user();

        if (!$user) {
            return response()->json([
                'message' => 'Utilizador não autenticado',
                'data' => null,
                'errors' => null,
            ], 404);
        }

        $video = Video::find($id);

        if (!$video) {
            return response()->json([
                'message' => 'Vídeo não encontrado',
                'data' => null,
                'errors' => null,
            ], 404);
        }

        $video->delete();
        return response()->json([
            'message' => 'Vídeo apagado com sucesso',
            'data' => null,
            'errors' => null,
        ], 200);
    }
}
