<?php

namespace Modules\Activity\Services;

use App\Services\DocumentService;
use Exception;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Modules\Activity\Entities\Activity;
use Modules\Activity\Repositories\Contracts\ActivityRepositoryInterface;

class ActivityService
{
    public function __construct(
        protected ActivityRepositoryInterface $repository,
        protected DocumentService $documentService,
    ) {}

    /**
     * @param  array<string, mixed>  $data
     * @param  array<int, UploadedFile>|array<string, UploadedFile>  $documents
     * @param  array<int, UploadedFile>  $galleryImages
     */
    public function create(array $data, array $documents = [], array $galleryImages = []): Activity
    {
        return DB::transaction(function () use ($data, $documents, $galleryImages) {
            $activity = $this->repository->create($data);

            $this->uploadDocuments($activity, $documents);
            $this->uploadGalleryImages($activity, $galleryImages);

            return $this->repository->findByIdWithRelations($activity->id);
        });
    }

    /**
     * @param  array<string, mixed>  $data
     * @param  array<int, UploadedFile>|array<string, UploadedFile>  $documents
     * @param  array<int, UploadedFile>  $galleryImages
     */
    public function update(Activity $activity, array $data, array $documents = [], array $galleryImages = []): Activity
    {
        return DB::transaction(function () use ($activity, $data, $documents, $galleryImages) {
            $activity->update($data);

            $this->uploadDocuments($activity, $documents);
            $this->uploadGalleryImages($activity, $galleryImages);

            return $this->repository->findByIdWithRelations($activity->id);
        });
    }

    public function uploadDocument(
        Activity $activity,
        UploadedFile $file,
        string $type = 'general',
        ?string $description = null
    ): Activity {
        if ($type === Activity::GALLERY_DOCUMENT_TYPE) {
            throw new Exception('Imej galeri mesti dimuat naik melalui endpoint galeri aktiviti.');
        }

        $this->documentService->validateFile($file);
        $this->documentService->uploadDocument($activity, $file, $type, $description);

        return $this->repository->findByIdWithRelations($activity->id);
    }

    public function uploadGalleryImage(
        Activity $activity,
        UploadedFile $file,
        ?string $description = null
    ): Activity {
        $this->validateGalleryImage($file);
        $this->documentService->uploadDocument(
            $activity,
            $file,
            Activity::GALLERY_DOCUMENT_TYPE,
            $description
        );

        return $this->repository->findByIdWithRelations($activity->id);
    }

    /**
     * @param  array<int, UploadedFile>|array<string, UploadedFile>  $documents
     */
    protected function uploadDocuments(Activity $activity, array $documents): void
    {
        foreach ($documents as $key => $file) {
            if (! $file instanceof UploadedFile) {
                continue;
            }

            $documentType = is_string($key) ? $key : 'general';

            if ($documentType === Activity::GALLERY_DOCUMENT_TYPE) {
                $this->validateGalleryImage($file);
                $this->documentService->uploadDocument($activity, $file, Activity::GALLERY_DOCUMENT_TYPE);

                continue;
            }

            $this->documentService->validateFile($file);
            $this->documentService->uploadDocument($activity, $file, $documentType);
        }
    }

    /**
     * @param  array<int, UploadedFile>  $galleryImages
     */
    protected function uploadGalleryImages(Activity $activity, array $galleryImages): void
    {
        foreach ($galleryImages as $file) {
            if (! $file instanceof UploadedFile) {
                continue;
            }

            $this->validateGalleryImage($file);
            $this->documentService->uploadDocument(
                $activity,
                $file,
                Activity::GALLERY_DOCUMENT_TYPE
            );
        }
    }

    protected function validateGalleryImage(UploadedFile $file): void
    {
        $validator = Validator::make(
            ['file' => $file],
            ['file' => 'required|file|mimes:jpg,jpeg,png,webp,gif|max:10240']
        );

        if ($validator->fails()) {
            throw new Exception($validator->errors()->first('file'));
        }
    }
}
