<?php

namespace App\Http\Controllers\Admin;

use App\Helpers\ApiResponse;
use App\Helpers\CacheHelper;
use App\Http\Controllers\Controller;
use App\Models\Media;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;

class MediaController extends Controller
{
    /**
     * Categories whose assets are curated centrally by the super admin.
     *
     * Everywhere else a franchisee works from their own uploads, but for these
     * four fields — program logo, program objective robots, workshop logo and
     * the workshop robot carousel — they pick from the admin's library instead.
     * Matched as prefixes because each category carries a per-program /
     * per-workshop slug (and, for super admins, a language suffix).
     */
    private const ADMIN_SOURCED_CATEGORIES = [
        'programlogo-',
        'programgallery_',
        'activitylogo-',
        'workshopgallery_',
    ];

    private function isAdminSourcedCategory(?string $category): bool
    {
        return !empty($category)
            && Str::startsWith($category, self::ADMIN_SOURCED_CATEGORIES);
    }

    public function uploadMediaFiles(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'mediafiles' => 'required|array',
            'mediafiles.*.file_name' => 'required|string',
            'mediafiles.*.url' => 'required|url',
            'mediafiles.*.type' => 'required|string',
            'mediafiles.*.media_category' => 'nullable|string',
            'mediafiles.*.size' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            return ApiResponse::error(
                $validator->errors()->first(),
                Response::HTTP_UNPROCESSABLE_ENTITY
            );
        }

        try {
            $user = Auth::user();

            // Categories only the super admin fills: the home banner, plus the
            // centrally-curated ones above. Franchisees can only *pick* from
            // these, so letting them upload here would create assets that are
            // invisible to them the moment the picker reopens.
            foreach ($request->mediafiles as $file) {
                $category = $file['media_category'] ?? null;

                if ($user->role !== 'super_admin'
                    && ($category === 'home_banner' || $this->isAdminSourcedCategory($category))
                ) {
                    return ApiResponse::error(
                        'Only super admins can upload media in this category.',
                        Response::HTTP_FORBIDDEN
                    );
                }
            }

            $franchiseeId = $user->role === 'super_admin' ? null : $user->franchisee_id;
            $insertedMedia = collect();

            foreach ($request->mediafiles as $file) {
                $media = Media::create([
                    'file_name' => $file['file_name'],
                    'url' => $file['url'],
                    'type' => $file['type'],
                    'media_category' => $file['media_category'] ?? null,
                    'size' => $file['size'] ?? null,
                    'franchisee_id' => $franchiseeId ?? null,
                    'uploaded_by' => $user->id ?? null,
                ]);

                $insertedMedia->push($media);
            }

            // Clear the media cache. A super admin's uploads feed every
            // franchisee's curated pickers, so their scope alone isn't enough —
            // flush the whole tag or the new asset stays invisible to
            // franchisees until the hour-long entries expire.
            if ($user->role === 'super_admin') {
                CacheHelper::flushRedisTag('media');
            } else {
                CacheHelper::forgetByTag('media');
            }

            return ApiResponse::success($insertedMedia, 'Media files uploaded successfully.');

        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    public function getMediaImages(Request $request)
    {
        $perPage = $request->get('per_page', 10);
        $page = $request->get('page', 1);
        $search = $request->get('search');
        $mediaCategory = $request->get('media_category');

        try {
            $user = Auth::user();

            // Whether this request is for one of the centrally-curated pickers.
            // Derived from the requested category server-side rather than taken
            // from the client, so it can't be flipped by hand.
            $adminSourced = $this->isAdminSourcedCategory($mediaCategory);

            // Create unique cache key based on filters. The viewer's role and
            // franchisee are part of the key because the result set now depends
            // on them — CacheHelper also namespaces by franchisee tag, but the
            // key stays explicit so the two can't drift apart.
            $cacheKey = 'media_' . md5(
                $search . '_' .
                $mediaCategory . '_' .
                $page . '_' .
                $perPage . '_' .
                $user->role . '_' .
                ($user->franchisee_id ?? 'global')
            );

            // Use CacheHelper's remember method which handles tags automatically
            $media = CacheHelper::rememberByTag('media', $cacheKey, function () use ($user, $page, $search, $perPage, $mediaCategory, $adminSourced) {
                $query = Media::query();

                // Search filter (optional)
                if (!empty($search)) {
                    $query->where(function ($q) use ($search) {
                        $q->where('file_name', 'like', "%{$search}%")
                            ->orWhere('type', 'like', "%{$search}%")
                            ->orWhere('url', 'like', "%{$search}%");
                    });
                }

                // Media category filter - support prefix matching
                if (!empty($mediaCategory)) {
                    $query->where('media_category', 'like', "{$mediaCategory}%");
                }

                // Ownership scoping — media is only visible to whoever uploaded
                // it. A null franchisee_id means the super admin uploaded it;
                // anything else belongs to that franchisee, and is shared with
                // their editors, who carry the same franchisee_id.
                //
                // The one crossover is the curated categories, where a
                // franchisee is shown the admin's library instead of their own.
                if ($user->role === 'super_admin' || $adminSourced) {
                    $query->whereNull('franchisee_id');
                } else {
                    $query->where('franchisee_id', $user->franchisee_id);
                }

                // Sort by latest
                $query->orderBy('created_at', 'desc');

                // Pagination
                return $query->paginate($perPage, ['*'], 'page', $page);
            });

            return ApiResponse::success($media, 'Media images fetched successfully.');

        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }

    public function deleteMedia(string $id)
    {
        try {
            $user = Auth::user();
            $media = Media::findOrFail($id);

            if ($user->role !== 'super_admin' && $media->franchisee_id !== $user->franchisee_id) {
                return ApiResponse::error('You are not authorized to delete this media.', Response::HTTP_FORBIDDEN);
            }

            $media->delete();

            // Same reasoning as upload: a removed admin asset must disappear
            // from every franchisee's curated picker, not just the admin's.
            if ($user->role === 'super_admin') {
                CacheHelper::flushRedisTag('media');
            } else {
                CacheHelper::forgetByTag('media');
            }

            return ApiResponse::success([], 'Media deleted successfully.');

        } catch (\Throwable $e) {
            return ApiResponse::exception($e);
        }
    }
}
