<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Models\Resource;
use App\Models\ResourceDownload;
use App\Models\ResourceRating;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

class ResourceController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $q = Resource::query()->with('author:id,name,username')
            ->where('status', 'published');

        if ($category = $request->query('category')) {
            $q->where('category', $category);
        }
        if ($tag = $request->query('tag')) {
            $q->whereJsonContains('tags', $tag);
        }
        if ($search = $request->query('q')) {
            $q->where(function ($w) use ($search): void {
                $w->where('title', 'like', "%{$search}%")
                  ->orWhere('description', 'like', "%{$search}%");
            });
        }

        $resources = $q->orderByDesc('published_at')
            ->paginate((int) $request->query('per_page', 20));

        return response()->json(['data' => $resources]);
    }

    public function show(string $slug): JsonResponse
    {
        $resource = Resource::with('author:id,name,username')
            ->where('slug', $slug)
            ->firstOrFail();

        // Increment view count (non-blocking)
        $resource->increment('view_count');

        // Related (same category, exclude self)
        $related = Resource::where('category', $resource->category)
            ->where('id', '!=', $resource->id)
            ->where('status', 'published')
            ->orderByDesc('download_count')
            ->limit(5)
            ->get(['id', 'slug', 'title', 'category', 'download_count', 'rating_avg']);

        return response()->json([
            'data' => $resource,
            'related' => $related,
        ]);
    }

    public function store(Request $request): JsonResponse
    {
        $this->authorizePerm($request, 'resources.create');

        $tenantId = app('currentTenant')->getKey();

        $data = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'slug' => [
                'nullable', 'string', 'max:191',
                Rule::unique('resources', 'slug')->where(fn ($q) => $q->where('tenant_id', $tenantId)),
            ],
            'description' => ['nullable', 'string'],
            'category' => ['required', Rule::in(['theme', 'skin', 'plugin', 'tip', 'manual_pdf'])],
            'tags' => ['nullable', 'array'],
            'file_path' => ['nullable', 'string', 'max:500'],
            'file_size' => ['nullable', 'integer'],
            'mime' => ['nullable', 'string', 'max:100'],
            'is_free' => ['nullable', 'boolean'],
            'price' => ['nullable', 'integer'],
            'required_member_level' => ['nullable', 'integer'],
            'status' => ['nullable', Rule::in(['draft', 'published', 'archived'])],
        ]);

        $data['tenant_id'] = $tenantId;
        $data['author_id'] = $request->user()?->id;
        $data['slug'] = $data['slug'] ?? Str::slug($data['title']).'-'.Str::lower(Str::random(5));
        $data['status'] = $data['status'] ?? 'draft';
        $data['is_free'] = $data['is_free'] ?? true;
        if ($data['status'] === 'published') {
            $data['published_at'] = now();
        }

        $resource = Resource::create($data);

        return response()->json(['data' => $resource], 201);
    }

    public function update(Request $request, string $id): JsonResponse
    {
        $this->authorizePerm($request, 'resources.update');

        $resource = Resource::findOrFail($id);
        $tenantId = app('currentTenant')->getKey();

        $data = $request->validate([
            'title' => ['sometimes', 'string', 'max:255'],
            'slug' => [
                'sometimes', 'string', 'max:191',
                Rule::unique('resources', 'slug')
                    ->where(fn ($q) => $q->where('tenant_id', $tenantId))
                    ->ignore($resource->id),
            ],
            'description' => ['nullable', 'string'],
            'category' => ['sometimes', Rule::in(['theme', 'skin', 'plugin', 'tip', 'manual_pdf'])],
            'tags' => ['nullable', 'array'],
            'file_path' => ['nullable', 'string', 'max:500'],
            'file_size' => ['nullable', 'integer'],
            'mime' => ['nullable', 'string', 'max:100'],
            'is_free' => ['nullable', 'boolean'],
            'price' => ['nullable', 'integer'],
            'required_member_level' => ['nullable', 'integer'],
            'status' => ['sometimes', Rule::in(['draft', 'published', 'archived'])],
        ]);

        if (isset($data['status']) && $data['status'] === 'published' && ! $resource->published_at) {
            $data['published_at'] = now();
        }

        $resource->update($data);

        return response()->json(['data' => $resource]);
    }

    public function destroy(Request $request, string $id): JsonResponse
    {
        $this->authorizePerm($request, 'resources.delete');

        $resource = Resource::findOrFail($id);
        $resource->delete();

        return response()->json(['data' => ['deleted' => true]]);
    }

    public function download(Request $request, string $id): JsonResponse
    {
        $resource = Resource::findOrFail($id);

        // Permission gate: paid / member-level
        if (! $resource->is_free && ! $request->user()) {
            throw new AccessDeniedHttpException('LOGIN_REQUIRED');
        }
        if ($resource->required_member_level && (! $request->user())) {
            throw new AccessDeniedHttpException('LOGIN_REQUIRED');
        }

        $tenantId = app('currentTenant')->getKey();
        ResourceDownload::create([
            'tenant_id' => $tenantId,
            'resource_id' => $resource->id,
            'user_id' => $request->user()?->id,
            'ip' => $request->ip(),
            'downloaded_at' => now(),
        ]);

        $resource->increment('download_count');

        return response()->json([
            'data' => [
                'resource_id' => $resource->id,
                'file_path' => $resource->file_path,
                'file_size' => $resource->file_size,
                'mime' => $resource->mime,
                'download_count' => $resource->download_count,
                'download_url' => $resource->file_path
                    ? '/storage/'.$resource->file_path
                    : null,
            ],
        ]);
    }

    public function rate(Request $request, string $id): JsonResponse
    {
        if (! $request->user()) {
            throw new AccessDeniedHttpException('UNAUTH');
        }

        $resource = Resource::findOrFail($id);

        $data = $request->validate([
            'rating' => ['required', 'integer', 'min:1', 'max:5'],
            'review' => ['nullable', 'string', 'max:2000'],
        ]);

        $rating = ResourceRating::updateOrCreate(
            ['resource_id' => $resource->id, 'user_id' => $request->user()->id],
            ['rating' => $data['rating'], 'review' => $data['review'] ?? null],
        );

        $stats = ResourceRating::where('resource_id', $resource->id)
            ->selectRaw('AVG(rating) as avg, COUNT(*) as cnt')
            ->first();

        $resource->update([
            'rating_avg' => round((float) ($stats->avg ?? 0), 2),
            'rating_count' => (int) ($stats->cnt ?? 0),
        ]);

        return response()->json([
            'data' => [
                'rating' => $rating,
                'rating_avg' => $resource->rating_avg,
                'rating_count' => $resource->rating_count,
            ],
        ]);
    }

    private function authorizePerm(Request $request, string $perm): void
    {
        $user = $request->user();
        if (! $user) {
            throw new AccessDeniedHttpException('UNAUTH');
        }
        if ($user->hasRole('super_admin') || $user->hasRole('tenant_admin')) {
            return;
        }
        if (! $user->can($perm)) {
            throw new AccessDeniedHttpException("PERM_DENIED:{$perm}");
        }
    }
}
