/home/bdqbpbxa/api-uniferx.goodface.com.ua/vendor/oneduo/nova-file-manager/src/Entities/Entity.php
<?php

declare(strict_types=1);

namespace Oneduo\NovaFileManager\Entities;

use Illuminate\Contracts\Support\Arrayable;
use Illuminate\fileSystem\AwsS3V3Adapter;
use Illuminate\Support\Carbon;
use Laravel\Nova\Http\Requests\NovaRequest;
use League\Flysystem\UnableToRetrieveMetadata;
use Oneduo\NovaFileManager\Contracts\Entities\Entity as EntityContract;
use Oneduo\NovaFileManager\Contracts\Services\FileManagerContract;

abstract class Entity implements Arrayable, EntityContract
{
    protected array $data = [];

    public function __construct(
        public FileManagerContract $manager,
        public string $path,
        public string $disk,
    ) {
    }

    /**
     * Static helper
     *
     * @param  \Oneduo\NovaFileManager\Contracts\Services\FileManagerContract  $manager
     * @param  string  $path
     * @param  string  $disk
     * @return static
     */
    public static function make(FileManagerContract $manager, string $path, string $disk): static
    {
        return new static($manager, $path, $disk);
    }

    /**
     * Return the entity's data as array
     *
     * @return array
     */
    public function toArray(): array
    {
        if (empty($this->data)) {
            $shouldAnalyze = config('nova-file-manager.file_analysis.enabled');

            if ($this->manager->filesystem()->exists($this->path)) {
                $this->data = array_merge(
                    [
                        'id' => $this->id(),
                        'disk' => $this->disk,
                        'name' => $this->name(),
                        'path' => $this->path,
                        'size' => $this->size(),
                        'extension' => $this->extension(),
                        'mime' => $this->mime(),
                        'url' => $this->url(),
                        'lastModifiedAt' => $this->lastModifiedAt(),
                        'type' => $this->type(),
                        'exists' => true,
                    ],
                    [
                        'meta' => $shouldAnalyze ? $this->meta() : [],
                    ],
                );
            } else {
                $this->data = array_merge([
                    'id' => $this->id(),
                    'disk' => $this->disk,
                    'path' => $this->path,
                    'exists' => false,
                ]);
            }
        }

        return $this->data;
    }

    /**
     * Generate a unique identifier for the entity
     *
     * @return string
     */
    public function id(): string
    {
        return sha1($this->manager->filesystem()->path($this->path));
    }

    /**
     * Get the name of the entity
     *
     * @return string
     */
    public function name(): string
    {
        return pathinfo($this->path, PATHINFO_BASENAME);
    }

    /**
     * Compute the size of the entity
     *
     * @return int|string
     */
    public function size(): int|string
    {
        $value = $this->manager->filesystem()->size($this->path);

        if (!config('nova-file-manager.human_readable_size')) {
            return $value;
        }

        $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];

        for ($i = 0; $value > 1024; $i++) {
            $value /= 1024;
        }

        return round($value, 2).' '.$units[$i];
    }

    /**
     * Get the file extension of the entity
     *
     * @return string
     */
    public function extension(): string
    {
        return pathinfo($this->path, PATHINFO_EXTENSION);
    }

    /**
     * Get the mime type of the entity
     *
     * @return string
     */
    public function mime(): string
    {
        try {
            $type = $this->manager->filesystem()->mimeType($this->path);

            if ($type === false) {
                throw UnableToRetrieveMetadata::mimeType($this->path);
            }

            return $type;
        } catch (UnableToRetrieveMetadata $e) {
            report($e);

            return 'application/octet-stream';
        }
    }

    /**
     * Build an url for the entity based on the disk
     *
     * @return string
     */
    public function url(): string
    {
        // if a custom url builder is defined, we use it to return the url
        if ($this->manager->hasUrlResolver()) {
            return call_user_func(
                $this->manager->getUrlResolver(),
                app(NovaRequest::class),
                $this->path,
                $this->disk,
                $this->manager->filesystem(),
            );
        }

        $supportsSignedUrls = $this->manager->filesystem() instanceof AwsS3V3Adapter;

        // signed urls are only supported on S3 disks
        if ($supportsSignedUrls && config('nova-file-manager.url_signing.enabled')) {
            return $this->manager->filesystem()->temporaryUrl(
                $this->path,
                $this->signedExpirationTime(),
            );
        }

        // we fallback to the regular url builder
        return $this->manager->filesystem()->url($this->path);
    }

    /**
     * Get the expiration time from the user defined config
     *
     * @return \Illuminate\Support\Carbon
     */
    public function signedExpirationTime(): Carbon
    {
        return now()->add(
            config('nova-file-manager.url_signing.unit'),
            config('nova-file-manager.url_signing.value'),
        );
    }

    /**
     * Get the last modified time of the entity as string
     *
     * @return string
     */
    public function lastModifiedAt(): string
    {
        if (!config('nova-file-manager.human_readable_datetime')) {
            return $this->lastModifiedAtTimestamp()->toDateTimeString();
        }

        return $this->lastModifiedAtTimestamp()->diffForHumans();
    }

    /**
     * Get the last modified time of the entity as a Carbon instance
     *
     * @return \Illuminate\Support\Carbon
     */
    public function lastModifiedAtTimestamp(): Carbon
    {
        return Carbon::createFromTimestamp($this->manager->filesystem()->lastModified($this->path));
    }

    /**
     * Define the type of the entity
     *
     * @return string
     */
    public function type(): string
    {
        $mime = str($this->mime());

        return match ((string) $mime->before('/')) {
            'image' => 'image',
            'video' => 'video',
            'audio' => 'audio',
            'text' => 'text',
            'application' => (string) $mime->afterLast('/'),
            default => 'unknown',
        };
    }

    abstract public function meta(): array;
}