<?php

declare(strict_types=1);


namespace App\Blog\Services;

use App\Models\Post;
use App\Support\MediaDisk;
use Illuminate\Support\Str;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

class AttachmentImporter
{
    /**
     * 将一条 sablog 附件记录写入媒体库。
     *
     * @param  array{attachmentid:int,articleid:int,dateline:int,filename:string,filetype:string,filesize:int,downloads:int,filepath:string,thumb_filepath:string,thumb_width:int,thumb_height:int,isimage:int}  $row
     */
    public function create(int $postId, array $row, ?string $attachmentsDir, bool $syncNow): Media
    {
        $legacyId = (int) ($row['attachmentid'] ?? 0);

        // 幂等：同一老附件已成功导入过则直接复用
        $existing = Media::query()
            ->where('collection_name', 'attachments')
            ->where('custom_properties->legacy_attachmentid', $legacyId)
            ->latest('id')
            ->first();

        if ($existing && ! $existing->getCustomProperty('pending_sync')) {
            return $existing;
        }

        $post = Post::find($postId);

        // 游离附件（articleid=0 或对应文章不存在）统一挂到 id=0 占位文章上
        if (! $post) {
            $post = new Post(['id' => 0]);
        }

        $properties = [
            'downloads' => (int) ($row['downloads'] ?? 0),
            'isimage' => (bool) ($row['isimage'] ?? false),
            'legacy_attachmentid' => (int) ($row['attachmentid'] ?? 0),
            'legacy_filepath' => $row['filepath'] ?? null,
            'legacy_thumb' => $row['thumb_filepath'] ?? null,
            'legacy_articleid' => (int) ($row['articleid'] ?? 0),
            'pending_sync' => true,
        ];

        $source = $this->locateSource($row['filepath'] ?? null, $attachmentsDir);

        if ($source && $syncNow) {
            try {
                $media = $post->addMedia($source)
                    ->preservingOriginal()
                    ->withCustomProperties($properties)
                    ->usingFileName(basename($row['filename']) ?: basename($source))
                    ->toMediaCollection('attachments', MediaDisk::name());

                $media->setCustomProperty('pending_sync', false);
                $media->save();

                return $media;
            } catch (\Throwable $e) {
                // addMedia 可能已插入记录并保存文件，仅缩略图生成失败：找回该记录标记完成
                $existing = Media::query()
                    ->where('collection_name', 'attachments')
                    ->where('custom_properties->legacy_attachmentid', (int) ($row['attachmentid'] ?? 0))
                    ->latest('id')
                    ->first();

                if ($existing) {
                    $existing->setCustomProperty('pending_sync', false);
                    $existing->save();

                    return $existing;
                }

                // 文件损坏无法入库时降级为 pending，不中断整批导入
                \Illuminate\Support\Facades\Log::warning('附件导入失败，已降级为待同步', [
                    'attachment' => $row['attachmentid'] ?? null,
                    'file' => $source,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        return $this->createPendingRecord($post->id, $row, $properties);
    }

    private function locateSource(?string $filepath, ?string $attachmentsDir): ?string
    {
        if (! $attachmentsDir || ! $filepath) {
            return null;
        }

        $candidate = rtrim($attachmentsDir, '/').'/'.ltrim($filepath, '/');

        return is_file($candidate) ? $candidate : null;
    }

    private function createPendingRecord(int $postId, array $row, array $properties): Media
    {
        $disk = MediaDisk::name();

        $media = new Media;
        $media->model_type = Post::class;
        $media->model_id = $postId;
        $media->uuid = (string) Str::uuid();
        $media->collection_name = 'attachments';
        $media->name = pathinfo($row['filename'] ?? 'attachment', PATHINFO_FILENAME) ?: 'attachment';
        $media->file_name = $row['filename'] ?: basename($row['filepath'] ?? 'attachment.bin');
        $media->mime_type = $row['filetype'] ?: null;
        $media->size = (int) ($row['filesize'] ?? 0);
        $media->disk = $disk;
        $media->conversions_disk = $disk;
        $media->manipulations = [];
        $media->custom_properties = $properties;
        $media->generated_conversions = [];
        $media->responsive_images = [];
        $media->save();

        return $media;
    }
}
