<?php

namespace App\Services\File;

use App\Http\Resources\API\FileDownloadResource;
use App\Models\Enums\FileObjectType;
use App\Models\Enums\FolderObjectType;
use App\Models\Enums\ShareFileObjectType;
use App\Models\File;
use App\Models\Folder;
use App\Models\ShareFile;
use Carbon\Carbon;
use Illuminate\Support\Collection;

class DownloadService
{
    public function downloadByIds(array $ids)
    {
        $files = File::query()->with(['folder'])->whereIn("id", $ids)->get();

        return $this->filesFormat($files);
    }

    /**
     * 下载分享文件
     *
     * @param string $uuid
     * @return array
     */
    public function downloadShareFile(string $uuid)
    {
        $shareFile = ShareFile::query()->where("uuid", $uuid)->firstOrFail();

        $objectType = ShareFileObjectType::from($shareFile->object_type);

        $objectType->modelBuilderAllowed($shareFile->object_id)->findOrFail($shareFile->object_id);
        $now = Carbon::now();
        $expirationTime = Carbon::parse($shareFile->expiration_time);
        if($now->gt($expirationTime)){
            return [];
        }
        $files = File::query()->with(['folder'])->whereIn("id", $shareFile->files)->get();

        return $this->filesFormat($files);
    }

    public function downloadAllLatest(string $objectType, string $objectId)
    {
        $folderObjectType = FolderObjectType::from($objectType);

        $object = $folderObjectType->modelBuilderAllowed()->findOrFail($objectId);

        $isExternalVersionControl = $this->isExternalVersionControl($folderObjectType);

        $fileIds = $isExternalVersionControl ? $this->versionFileIds($folderObjectType, $object) : [];

        $files = File::query()->with(['folder'])->where([
            'object_type' => $objectType,
            'object_id' => $objectId,
        ])->when(! $isExternalVersionControl, fn($query) => $query->where("is_latest_version", 1))
            ->when($fileIds, fn($query) => $query->whereIn("id", $fileIds))
            ->orderByDesc("version")
            ->get();

        $files = $isExternalVersionControl ? $this->getLatestFiles($files, $object) : $files;

        return $this->filesFormat($files);
    }

    protected function isExternalVersionControl(FolderObjectType $folderObjectType)
    {
        return $folderObjectType == FolderObjectType::CONTAINER && request("object_version", 0) > 0;
    }

    protected function getLatestFiles(Collection $files, $object)
    {
        $objectVersion = request('object_version') ?: $object->version;

        $items = [];

        foreach ($files->groupBy("folder_id") as $folderFiles) {
            foreach ($folderFiles as $file) {
                $isHide = $file->hide_object_version == 0
                    ? (bool)$file->is_hide
                    : $file->is_hide  && $file->hide_object_version <= $objectVersion;
                if (! $isHide) {
                    $items[] = $file;
                    break;
                }
            }
        }

        return collect($items);
    }

    protected function versionFileIds(FolderObjectType $folderObjectType, $object)
    {
        $fileIds = [];
        if ($folderObjectType == FolderObjectType::CONTAINER) {
            $containerContent = $object->content(request('object_version') ?: $object->version)->first();

            throw_validation_if(! $containerContent, "The current version does not exist");

            $fileIds = explode(",", $containerContent->files);
        }

        return array_unique(array_filter($fileIds));
    }

    protected function filesFormat(Collection $files)
    {
        $folderIds = [];
        foreach ($files as $file) {
            $folderIds = [...$folderIds, ...explode(",", $file->folder?->path)];
        }

        $folders = Folder::query()->whereIn("id", array_unique(array_filter($folderIds)))->pluck("name", "id");

        $items = [];
        foreach ($files as $file) {
            $object = FileObjectType::from($file->object_type)
                ->modelBuilderAllowed($file->object_id)
                ->find($file->object_id);

            throw_validation_if(! $object, sprintf("File ID: %s, no permission to access", $file->id));

            $fileDownloadResource = (new FileDownloadResource($file))->toArray(request());

            $folderPath = [];
            foreach(array_filter(explode(",", $file->folder?->path)) as $folderId) {
                $folderPath[] = $folders->get($folderId);
            }

            $fileDownloadResource['folder_path'] = "/" . implode('/', $folderPath);

            $items[] = $fileDownloadResource;
        }

        return $items;
    }
}