<?php

declare(strict_types=1);

namespace App\Filament\Support;

use App\Business\Settlement\Enums\SettlementDocumentStatus;
use App\Support\DberpPrivateStorageServeUrl;
use Filament\Forms\Components\BaseFileUpload;
use Filament\Forms\Components\FileUpload;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;

/**
 * 结算收付款等单据的附件/凭证上传字段。
 */
final class DberpFilamentAttachmentFields
{
    /**
     * 草稿、已提交状态允许补传凭证；生效/作废后只读。
     */
    public static function isSettlementVoucherEditable(?Model $record): bool
    {
        if ($record === null) {
            return true;
        }

        $status = $record->getAttribute('status');

        if (! is_string($status)) {
            return false;
        }

        return in_array($status, [
            SettlementDocumentStatus::Draft->value,
            SettlementDocumentStatus::Submitted->value,
        ], true);
    }

    public static function voucherAttachments(string $storageDirectory): FileUpload
    {
        return FileUpload::make('attachment_paths')
            ->label(__('dberp.fields.voucher_attachment'))
            ->helperText(__('dberp.hints.voucher_attachment'))
            ->disk('local')
            ->directory($storageDirectory)
            ->visibility('private')
            // 与 Livewire 临时盘同为 local，提交表单时从 livewire-tmp 移动而非复制，减少临时文件丢失导致落盘失败。
            ->moveFiles()
            ->multiple()
            ->maxFiles(10)
            ->acceptedFileTypes([
                'application/pdf',
                'image/jpeg',
                'image/png',
                'image/webp',
            ])
            ->maxSize(10_240)
            ->downloadable()
            ->openable()
            ->previewable()
            ->reorderable()
            ->getUploadedFileUsing(
                fn (BaseFileUpload $component, string $file, string|array|null $storedFileNames): ?array => self::describeStoredUpload(
                    $file,
                    $storedFileNames,
                    $component->isMultiple(),
                ),
            )
            ->getOpenableFileUrlUsing(
                fn (BaseFileUpload $component, string $file): ?string => app(DberpPrivateStorageServeUrl::class)->forPath($file),
            )
            ->getDownloadableFileUrlUsing(
                fn (BaseFileUpload $component, string $file): ?string => app(DberpPrivateStorageServeUrl::class)->forPath($file),
            )
            ->columnSpanFull();
    }

    /**
     * @param  string|array<string, string>|null  $storedFileNames
     * @return array{name: string, size: int, type: ?string, url: ?string}|null
     */
    private static function describeStoredUpload(
        string $file,
        string|array|null $storedFileNames,
        bool $isMultiple,
    ): ?array {
        $storage = Storage::disk(DberpPrivateStorageServeUrl::DISK);

        if (! $storage->exists($file)) {
            return null;
        }

        $url = app(DberpPrivateStorageServeUrl::class)->forPath($file);

        if ($url === null) {
            return null;
        }

        return [
            'name' => ($isMultiple ? ($storedFileNames[$file] ?? null) : $storedFileNames) ?? basename($file),
            'size' => $storage->size($file),
            'type' => $storage->mimeType($file),
            'url' => $url,
        ];
    }
}
