<?php

declare(strict_types=1);

namespace app\common\library\upload\driver;

use ba\Filesystem;
use app\common\library\upload\Driver;
use app\common\library\upload\WebmanUploadedFile;
use RuntimeException;

/**
 * 上传到本地磁盘的驱动（Webman 迁移版）
 */
class Local extends Driver
{
    protected array $options = [];

    public function __construct(array $options = [])
    {
        $this->options = config('filesystem.disks.public', []);
        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }
    }

    public function save(WebmanUploadedFile $file, string $saveName): bool
    {
        $savePathInfo = pathinfo($saveName);
        $saveFullPath = $this->getFullPath($saveName);
        $destination = rtrim($saveFullPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $savePathInfo['basename'];

        $saveDir = dirname($destination);
        if (!is_dir($saveDir) && !@mkdir($saveDir, 0755, true)) {
            throw new RuntimeException(__('Failed to create upload directory'));
        }

        $uploadFile = $file->getUploadFile();
        $uploadFile->move($destination);
        @chmod($destination, 0666 & ~umask());
        return true;
    }

    public function delete(string $saveName): bool
    {
        $saveFullName = $this->getFullPath($saveName, true);
        if ($this->exists($saveFullName)) {
            @unlink($saveFullName);
        }
        Filesystem::delEmptyDir(dirname($saveFullName));
        return true;
    }

    public function url(string $saveName, string|bool $domain = true, string $default = ''): string
    {
        $saveName = $this->clearRootPath($saveName);
        $saveName = $saveName ? '/' . ltrim(str_replace('\\', '/', $saveName), '/') : '';

        if ($domain === true) {
            $req = function_exists('request') ? request() : null;
            $domain = $req && method_exists($req, 'host') ? '//' . $req->host() : '';
        } elseif ($domain === false) {
            $domain = '';
        }

        $saveName = $saveName ?: $default;
        if (!$saveName) return $domain;

        $regex = "/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i";
        if (preg_match('/^http(s)?:\/\//', $saveName) || preg_match($regex, $saveName) || $domain === false) {
            return $saveName;
        }
        return str_replace('\\', '/', $domain . $saveName);
    }

    public function exists(string $saveName): bool
    {
        $saveFullName = $this->getFullPath($saveName, true);
        return file_exists($saveFullName);
    }

    public function getFullPath(string $saveName, bool $baseName = false): string
    {
        $savePathInfo = pathinfo($saveName);
        $root = $this->getRootPath();
        $dirName = $savePathInfo['dirname'] . '/';

        if (str_starts_with($saveName, $root)) {
            return Filesystem::fsFit($baseName || !isset($savePathInfo['extension']) ? $saveName : $dirName);
        }

        return Filesystem::fsFit($root . $dirName . ($baseName ? $savePathInfo['basename'] : ''));
    }

    public function clearRootPath(string $saveName): string
    {
        return str_replace($this->getRootPath(), '', Filesystem::fsFit($saveName));
    }

    public function getRootPath(): string
    {
        $root = $this->options['root'] ?? rtrim(base_path(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'public';
        return Filesystem::fsFit($root);
    }
}
