<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Models\Feature;
use App\Models\Issue;
use App\Models\IssueComment;
use App\Models\IssueTask;
use App\Models\Layer;
use App\Models\Media;
use App\Models\Phase;
use App\Models\Project;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;

class MediaController extends Controller
{
    private array $map = [
        'feature' => Feature::class,
        'issue' => Issue::class,
        'issue_task' => IssueTask::class,
        'issue_comment' => IssueComment::class,
        'project' => Project::class,
        'phase' => Phase::class,
        'layer' => Layer::class,
    ];

    /** Upload a file (multipart) and attach it to a parent record. Idempotent by uuid. */
    public function upload(Request $request)
    {
        $data = $request->validate([
            'uuid' => ['required', 'uuid'],
            'parent_entity' => ['required', Rule::in(array_keys($this->map))],
            'parent_id' => ['required', 'integer'],
            'file' => ['required', 'file', 'max:20480'], // 20 MB
            'category' => ['nullable', 'in:image,document,other'],
            'description' => ['nullable', 'string'],
        ]);

        // Idempotency: same uuid already uploaded → return it.
        if ($existing = Media::where('uuid', $data['uuid'])->first()) {
            return response()->json(['status' => 'duplicate', 'media' => $this->payload($existing)]);
        }

        $parent = $this->map[$data['parent_entity']]::find($data['parent_id']);
        if (! $parent) {
            return response()->json(['status' => 'error', 'error' => 'parent not found'], 422);
        }

        $user = $request->user();
        $project = $this->projectOf($data['parent_entity'], $parent);
        abort_unless($this->canAccess($user, $project) && $user->can('upload media'), 403);

        $file = $request->file('file');
        $path = $file->store("media/{$data['parent_entity']}/{$parent->id}", 'public');
        $mime = $file->getClientMimeType();

        $media = $parent->media()->create([
            'uuid' => $data['uuid'],
            'name' => $file->getClientOriginalName(),
            'file_path' => $path,
            'file_type' => $mime,
            'file_extension' => $file->getClientOriginalExtension(),
            'file_size' => $file->getSize(),
            'category' => $data['category'] ?? (Str::startsWith($mime, 'image/') ? 'image' : 'document'),
            'description' => $data['description'] ?? null,
            'uploaded_by' => $user->id,
            'client_updated_at' => $request->input('client_updated_at'),
        ]);

        return response()->json(['status' => 'applied', 'media' => $this->payload($media)]);
    }

    private function projectOf(string $entity, $parent): ?Project
    {
        return match ($entity) {
            'project' => $parent,
            'phase' => $parent->project,
            'layer' => $parent->phase?->project,
            'feature' => $parent->layer?->phase?->project,
            'issue' => $parent->project,
            'issue_task' => $parent->issue?->project,
            'issue_comment' => $parent->issue?->project,
            default => null,
        };
    }

    private function canAccess(User $user, ?Project $project): bool
    {
        if (! $project) {
            return false;
        }

        return $user->can('manage all')
            || $project->users()->where('user_id', $user->id)->exists();
    }

    private function payload(Media $m): array
    {
        return [
            'id' => $m->id,
            'uuid' => $m->uuid,
            'url' => $m->url,
            'name' => $m->name,
            'file_type' => $m->file_type,
            'category' => $m->category,
            'updated_at' => $m->updated_at?->toIso8601String(),
        ];
    }
}
