<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Media;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class MediaController extends Controller
{
    public function index(Request $request)
    {
        $media = $this->mediaQuery($request)
            ->withCount('usages')
            ->orderBy('sort_order')
            ->orderByDesc('created_at')
            ->paginate(24)
            ->withQueryString();

        return view('admin.media.index', compact('media'));
    }

    public function browser(Request $request)
    {
        $media = $this->mediaQuery($request)
            ->withCount('usages')
            ->orderBy('sort_order')
            ->orderByDesc('created_at')
            ->paginate(18)
            ->withQueryString();

        if ($request->wantsJson()) {
            return response()->json([
                'data' => $media->getCollection()->map(fn (Media $item): array => $this->formatMedia($item))->values(),
            ]);
        }

        return view('admin.media.browser', compact('media'));
    }

    public function details(Media $media): JsonResponse
    {
        return response()->json($this->formatMedia($media->loadCount('usages')));
    }

    public function reorder(Request $request)
    {
        $request->validate([
            'order' => 'required|array',
            'order.*' => 'integer|exists:media,id',
        ]);

        foreach ($request->input('order') as $index => $id) {
            Media::where('id', $id)->update(['sort_order' => $index]);
        }

        return response()->json(['status' => 'ok']);
    }

    public function store(Request $request)
    {
        $request->validate([
            'file' => 'required|file|max:10240',
            'name' => 'nullable|string|max:255',
            'type' => 'nullable|string|max:50',
            'category' => 'nullable|string|max:50',
            'alt_text' => 'nullable|string|max:255',
        ]);

        $uploaded = $request->file('file');
        $path = $uploaded->store('uploads/media', 'public');
        $meta = $this->extractMetadata($uploaded, $path);

        Media::create([
            'name' => $request->input('name') ?: pathinfo($uploaded->getClientOriginalName(), PATHINFO_FILENAME),
            'file_path' => $path,
            'disk' => 'public',
            'type' => $request->input('type') ?: Str::before((string) ($meta['mime_type'] ?? $uploaded->getMimeType()), '/'),
            'mime_type' => $meta['mime_type'],
            'extension' => $meta['extension'],
            'size' => $meta['size'],
            'width' => $meta['width'],
            'height' => $meta['height'],
            'category' => $request->input('category') ?: $this->inferCategory($meta['mime_type']),
            'is_system' => false,
            'uploaded_by' => $request->user()?->id,
            'alt_text' => $request->input('alt_text'),
            'sort_order' => (int) Media::max('sort_order') + 1,
        ]);

        return redirect()->route('admin.media.index')->with('success', 'Media uploaded successfully.');
    }

    public function replace(Request $request, Media $media)
    {
        $request->validate([
            'file' => 'required|file|max:10240',
            'name' => 'nullable|string|max:255',
            'alt_text' => 'nullable|string|max:255',
            'category' => 'nullable|string|max:50',
        ]);

        $uploaded = $request->file('file');
        $path = $uploaded->store('uploads/media', 'public');
        $meta = $this->extractMetadata($uploaded, $path);

        if (filled($media->file_path) && Storage::disk($media->disk ?: 'public')->exists($media->file_path)) {
            Storage::disk($media->disk ?: 'public')->delete($media->file_path);
        }

        $media->update([
            'name' => $request->input('name') ?: $media->name ?: pathinfo($uploaded->getClientOriginalName(), PATHINFO_FILENAME),
            'file_path' => $path,
            'disk' => 'public',
            'mime_type' => $meta['mime_type'],
            'extension' => $meta['extension'],
            'size' => $meta['size'],
            'width' => $meta['width'],
            'height' => $meta['height'],
            'category' => $request->input('category') ?: $media->category ?: $this->inferCategory($meta['mime_type']),
            'alt_text' => $request->input('alt_text', $media->alt_text),
            'uploaded_by' => $request->user()?->id,
        ]);

        return back()->with('success', 'Media updated successfully.');
    }

    public function destroy(Media $media)
    {
        if ($media->usages()->exists()) {
            return redirect()->route('admin.media.index')->with('error', 'This media item is currently used on the site and cannot be deleted yet.');
        }

        if (Storage::disk($media->disk ?: 'public')->exists($media->file_path)) {
            Storage::disk($media->disk ?: 'public')->delete($media->file_path);
        }

        $media->delete();

        return redirect()->route('admin.media.index')->with('success', 'Media deleted successfully.');
    }

    public function bulkDestroy(Request $request)
    {
        $ids = $request->input('ids', []);

        if (is_string($ids)) {
            $ids = array_filter(explode(',', $ids));
        }

        $mediaItems = Media::whereIn('id', (array) $ids)->get();
        $deleted = 0;
        $skipped = 0;

        if ($mediaItems->isEmpty()) {
            return redirect()->route('admin.media.index')->with('error', 'No media items were selected for deletion.');
        }

        foreach ($mediaItems as $media) {
            if ($media->usages()->exists()) {
                $skipped++;
                continue;
            }

            if (Storage::disk($media->disk ?: 'public')->exists($media->file_path)) {
                Storage::disk($media->disk ?: 'public')->delete($media->file_path);
            }

            $media->delete();
            $deleted++;
        }

        $redirect = redirect()->route('admin.media.index');

        if ($deleted > 0) {
            $redirect->with('success', $deleted === 1
                ? '1 media item deleted successfully.'
                : "{$deleted} media items deleted successfully.");
        }

        if ($skipped > 0) {
            $redirect->with('error', $skipped === 1
                ? '1 media item was skipped because it is currently used on the site.'
                : "{$skipped} media items were skipped because they are currently used on the site.");
        }

        if ($deleted === 0 && $skipped === 0) {
            $redirect->with('error', 'No media items were deleted.');
        }

        return $redirect;
    }

    protected function mediaQuery(Request $request): Builder
    {
        return Media::query()
            ->when($request->filled('search'), function (Builder $query) use ($request): Builder {
                $search = '%' . $request->string('search') . '%';

                return $query->where(function (Builder $builder) use ($search): void {
                    $builder
                        ->where('name', 'like', $search)
                        ->orWhere('file_path', 'like', $search)
                        ->orWhere('alt_text', 'like', $search);
                });
            })
            ->when($request->filled('category'), fn (Builder $query): Builder => $query->where('category', $request->string('category')))
            ->when($request->filled('type'), fn (Builder $query): Builder => $query->where('type', $request->string('type')))
            ->orderByRaw("CASE 
                WHEN category IN ('service-image', 'service-icon') AND file_path LIKE 'uploads/media/%' THEN 0
                WHEN category IN ('service-image', 'service-icon') AND file_path LIKE 'uploads/system/%' THEN 2
                ELSE 1
            END");
    }

    protected function formatMedia(Media $item): array
    {
        return [
            'id' => $item->id,
            'name' => $item->name,
            'alt_text' => $item->alt_text,
            'category' => $item->category,
            'type' => $item->type,
            'mime_type' => $item->mime_type,
            'file_path' => $item->file_path,
            'url' => $item->url,
            'preview_url' => $item->preview_url,
            'is_image' => $item->is_image,
            'usage_count' => $item->usages_count ?? $item->usages()->count(),
            'is_original_upload' => $item->is_original_upload,
            'is_system_duplicate' => $item->is_system_duplicate,
            'media_guidance_label' => $item->media_guidance_label,
            'media_guidance_text' => $item->media_guidance_text,
        ];
    }

    protected function extractMetadata($uploaded, string $path): array
    {
        $meta = [
            'mime_type' => $uploaded->getMimeType(),
            'extension' => strtolower((string) $uploaded->getClientOriginalExtension()),
            'size' => $uploaded->getSize(),
            'width' => null,
            'height' => null,
        ];

        try {
            $absolutePath = Storage::disk('public')->path($path);
            $imageSize = @getimagesize($absolutePath);

            if ($imageSize !== false) {
                $meta['width'] = $imageSize[0] ?? null;
                $meta['height'] = $imageSize[1] ?? null;
            }
        } catch (\Throwable) {
            // Ignore metadata extraction failures and keep the upload usable.
        }

        return $meta;
    }

    protected function inferCategory(?string $mimeType): string
    {
        if ($mimeType && str_starts_with($mimeType, 'image/')) {
            return 'image';
        }

        if ($mimeType && str_starts_with($mimeType, 'video/')) {
            return 'video';
        }

        return 'document';
    }
}
