<?php

namespace App\Jobs;

use App\Models\Document;
use App\Services\DocumentConversionService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

/**
 * 文档转换为 Markdown 的队列任务
 */
class ConvertDocumentToMarkdown implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * 任务最大尝试次数
     *
     * @var int
     */
    public $tries;

    /**
     * 任务超时时间（秒）
     *
     * @var int
     */
    public $timeout;

    /**
     * 重试延迟（秒）
     *
     * @var int
     */
    public $backoff;

    /**
     * 文档实例
     *
     * @var Document
     */
    protected Document $document;

    /**
     * 创建新的任务实例
     *
     * @param Document $document
     */
    public function __construct(Document $document)
    {
        $this->document = $document;
        $this->tries = config('documents.conversion.retry_times', 3);
        $this->timeout = config('documents.conversion.timeout', 300);
        $this->backoff = config('documents.conversion.retry_delay', 60);
    }

    /**
     * 执行任务
     *
     * @param DocumentConversionService $conversionService
     * @return void
     */
    public function handle(DocumentConversionService $conversionService): void
    {
        try {
            Log::info('开始转换文档', [
                'document_id' => $this->document->id,
                'document_title' => $this->document->title,
                'attempt' => $this->attempts(),
            ]);

            // 转换文档为 Markdown
            $result = $conversionService->convertToMarkdown($this->document);
            $markdown = $result['markdown'];
            $mediaDir = $result['mediaDir'] ?? null;
            $tempDir = $result['tempDir'];
            $tempDirName = $result['tempDirName'];

            try {
                // 保存 Markdown 文件和媒体文件
                $markdownPath = $conversionService->saveMarkdownToFile($this->document, $markdown, $mediaDir);

                // 更新文档的 Markdown 信息
                $conversionService->updateDocumentMarkdown($this->document, $markdownPath);
            } finally {
                // 清理临时目录
                if (isset($tempDirName) && \Storage::disk('local')->exists($tempDirName)) {
                    \Storage::disk('local')->deleteDirectory($tempDirName);
                }
            }

            Log::info('文档转换成功', [
                'document_id' => $this->document->id,
                'document_title' => $this->document->title,
                'markdown_path' => $markdownPath,
            ]);

            // 转换成功后，触发索引（如果需要）
            // 这将在后续任务中实现
            // $this->document->searchable();

        } catch (\Exception $e) {
            Log::error('文档转换失败', [
                'document_id' => $this->document->id,
                'document_title' => $this->document->title,
                'attempt' => $this->attempts(),
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            // 如果已达到最大重试次数，标记为失败
            if ($this->attempts() >= $this->tries) {
                $conversionService->handleConversionFailure($this->document, $e);
            }

            // 重新抛出异常以触发重试
            throw $e;
        }
    }

    /**
     * 任务失败时的处理
     *
     * @param \Throwable $exception
     * @return void
     */
    public function failed(\Throwable $exception): void
    {
        Log::error('文档转换任务最终失败', [
            'document_id' => $this->document->id,
            'document_title' => $this->document->title,
            'error' => $exception->getMessage(),
        ]);

        // 确保文档状态被标记为失败
        $conversionService = app(DocumentConversionService::class);
        $conversionService->handleConversionFailure(
            $this->document,
            $exception instanceof \Exception ? $exception : new \Exception($exception->getMessage())
        );
    }

    /**
     * 递归删除目录
     *
     * @param string $dir 目录路径
     * @return void
     */
    protected function deleteDirectory(string $dir): void
    {
        if (!file_exists($dir)) {
            return;
        }

        if (!is_dir($dir)) {
            unlink($dir);
            return;
        }

        $files = array_diff(scandir($dir), ['.', '..']);
        foreach ($files as $file) {
            $path = $dir . '/' . $file;
            if (is_dir($path)) {
                $this->deleteDirectory($path);
            } else {
                unlink($path);
            }
        }

        rmdir($dir);
    }
}

