<?php

declare(strict_types=1);

namespace App\Services\Install;

use Illuminate\Support\Facades\File;
use RuntimeException;

/**
 * 校验或创建 public/storage → storage/app/public 符号链接（Web 安装收尾）。
 */
final class InstallPublicStorageLinkGuard
{
    public function publicStoragePath(): string
    {
        return public_path('storage');
    }

    public function publicStorageTargetPath(): string
    {
        return storage_path('app/public');
    }

    /**
     * 移除无效的 public/storage（发布包误带的真目录、错误链接等），保留已指向 storage/app/public 的有效链接。
     *
     * @throws RuntimeException
     */
    public function removeInvalidPublicStoragePath(): bool
    {
        $link = $this->publicStoragePath();
        $target = $this->publicStorageTargetPath();

        if ($this->isValidLink($link, $target)) {
            return false;
        }

        if (! file_exists($link) && ! is_link($link)) {
            return false;
        }

        $this->deletePublicStoragePath($link);

        return true;
    }

    /**
     * @throws RuntimeException
     */
    public function ensureLinkExists(): void
    {
        $this->removeInvalidPublicStoragePath();

        if (file_exists($this->publicStoragePath()) || is_link($this->publicStoragePath())) {
            throw new RuntimeException('公共存储目录链接创建失败，请检查 public/storage 是否被占用。');
        }
    }

    /**
     * @throws RuntimeException
     */
    private function deletePublicStoragePath(string $path): void
    {
        if (is_link($path) || is_file($path)) {
            if (@unlink($path)) {
                return;
            }

            throw new RuntimeException('无法删除无效的 public/storage，请检查目录权限后重试。');
        }

        if (! is_dir($path)) {
            return;
        }

        try {
            File::deleteDirectory($path);
        } catch (\Throwable $e) {
            throw new RuntimeException('无法删除无效的 public/storage 目录，请检查目录权限后重试。', 0, $e);
        }
    }

    public function isPublicDirectoryWritable(): bool
    {
        $public = public_path();

        if (! is_dir($public)) {
            return false;
        }

        return is_writable($public);
    }

    public function isValidLink(string $link, string $target): bool
    {
        if (! file_exists($link) && ! is_link($link)) {
            return false;
        }

        $resolvedTarget = realpath($target);

        if ($resolvedTarget === false) {
            return false;
        }

        $resolvedLink = realpath($link);

        return $resolvedLink !== false && $resolvedLink === $resolvedTarget;
    }
}
