<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreAttachmentRequest;
use App\Models\Attachment;
use App\Models\Booking;
use App\Models\Customer;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Quotation;
use App\Services\AttachmentService;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\RedirectResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;

class AttachmentController extends Controller
{
    public function __construct(
        private readonly AttachmentService $attachments,
    ) {}

    public function store(StoreAttachmentRequest $request, string $type, int $id): RedirectResponse
    {
        $attachable = $this->resolveAttachable($type, $id);

        $this->authorize('create', Attachment::class);
        $this->authorizeAttachableView($attachable);

        $this->attachments->store(
            $request->file('file'),
            $attachable,
            $request->user(),
            $request->input('description'),
        );

        return back()->with('success', 'Attachment uploaded successfully.');
    }

    public function download(Attachment $attachment): StreamedResponse
    {
        $this->authorize('download', $attachment);

        return $this->attachments->download($attachment);
    }

    public function destroy(Attachment $attachment): RedirectResponse
    {
        $this->authorize('delete', $attachment);

        $this->attachments->delete($attachment);

        return back()->with('success', 'Attachment deleted.');
    }

    private function resolveAttachable(string $type, int $id): Model
    {
        $map = [
            'customers' => Customer::class,
            'bookings' => Booking::class,
            'quotations' => Quotation::class,
            'invoices' => Invoice::class,
            'payments' => Payment::class,
        ];

        if (! isset($map[$type])) {
            abort(404);
        }

        /** @var class-string<Model> $modelClass */
        $modelClass = $map[$type];

        return $modelClass::query()->findOrFail($id);
    }

    private function authorizeAttachableView(Model $attachable): void
    {
        $permission = match ($attachable::class) {
            Customer::class => 'customers.view',
            Booking::class => 'bookings.view',
            Quotation::class => 'quotations.view',
            Invoice::class => 'invoices.view',
            Payment::class => 'payments.view',
            default => null,
        };

        if ($permission !== null && ! request()->user()?->hasPermission($permission)) {
            abort(403);
        }
    }
}
