<?php

namespace App\Services;

use App\Models\Document;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;

/**
 * 文档搜索服务
 * 负责处理文档的全文搜索和 Meilisearch 索引管理
 */
class DocumentSearchService
{
    /**
     * 搜索文档
     * 使用 Laravel Scout 和 Meilisearch 进行全文搜索
     *
     * @param string $query 搜索关键词
     * @param User $user 当前用户
     * @param array $filters 额外的筛选条件
     * @return Collection
     */
    public function search(string $query, User $user, array $filters = []): Collection
    {
        try {
            // 使用 Scout 进行搜索
            $searchBuilder = Document::search($query);

            // 应用额外的筛选条件
            if (!empty($filters['type'])) {
                $searchBuilder->where('type', $filters['type']);
            }

            if (!empty($filters['group_id'])) {
                $searchBuilder->where('group_id', $filters['group_id']);
            }

            if (!empty($filters['uploaded_by'])) {
                $searchBuilder->where('uploaded_by', $filters['uploaded_by']);
            }

            // 执行搜索并获取结果
            $results = $searchBuilder->get();

            // 应用用户权限过滤
            return $this->filterByUserPermissions($results, $user);
        } catch (\Exception $e) {
            Log::error('文档搜索失败', [
                'query' => $query,
                'user_id' => $user->id,
                'filters' => $filters,
                'error' => $e->getMessage(),
            ]);

            // 搜索失败时返回空集合
            return new Collection();
        }
    }

    /**
     * 根据用户权限过滤搜索结果
     * 确保用户只能看到有权限访问的文档
     *
     * @param Collection $results 搜索结果
     * @param User $user 当前用户
     * @return Collection
     */
    public function filterByUserPermissions(Collection $results, User $user): Collection
    {
        // 获取用户所属的所有分组 ID
        $userGroupIds = $user->groups()->pluck('groups.id')->toArray();

        return $results->filter(function (Document $document) use ($userGroupIds) {
            // 全局文档对所有用户可见
            if ($document->type === 'global') {
                return true;
            }

            // 专用文档只对所属分组的用户可见
            if ($document->type === 'dedicated') {
                return in_array($document->group_id, $userGroupIds);
            }

            return false;
        });
    }

    /**
     * 准备文档的可搜索数据
     * 包含完整的 Markdown 内容用于索引
     *
     * @param Document $document 文档模型
     * @return array
     */
    public function prepareSearchableData(Document $document): array
    {
        return [
            'id' => $document->id,
            'title' => $document->title,
            'description' => $document->description,
            'markdown_content' => $document->getMarkdownContent(),
            'type' => $document->type,
            'group_id' => $document->group_id,
            'uploaded_by' => $document->uploaded_by,
            'created_at' => $document->created_at?->timestamp,
            'updated_at' => $document->updated_at?->timestamp,
        ];
    }

    /**
     * 索引文档到 Meilisearch
     * 读取 Markdown 文件并创建搜索索引
     *
     * @param Document $document 文档模型
     * @return void
     */
    public function indexDocument(Document $document): void
    {
        try {
            // 只索引已完成转换的文档
            if (!$document->shouldBeSearchable()) {
                Log::info('文档未完成转换，跳过索引', [
                    'document_id' => $document->id,
                    'conversion_status' => $document->conversion_status,
                ]);
                return;
            }

            // 使用 Scout 的 searchable 方法进行索引
            $document->searchable();

            Log::info('文档索引成功', [
                'document_id' => $document->id,
                'title' => $document->title,
            ]);
        } catch (\Exception $e) {
            Log::error('文档索引失败', [
                'document_id' => $document->id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            // 索引失败不影响文档的正常使用，只记录错误
        }
    }

    /**
     * 更新文档在 Meilisearch 中的索引
     *
     * @param Document $document 文档模型
     * @return void
     */
    public function updateDocumentIndex(Document $document): void
    {
        try {
            // 如果文档应该被索引，则更新索引
            if ($document->shouldBeSearchable()) {
                $document->searchable();

                Log::info('文档索引更新成功', [
                    'document_id' => $document->id,
                    'title' => $document->title,
                ]);
            } else {
                // 如果文档不应该被索引（例如转换失败），则从索引中移除
                $this->removeDocumentFromIndex($document);
            }
        } catch (\Exception $e) {
            Log::error('文档索引更新失败', [
                'document_id' => $document->id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            // 索引更新失败不影响文档的正常使用，只记录错误
        }
    }

    /**
     * 从 Meilisearch 中移除文档索引
     *
     * @param Document $document 文档模型
     * @return void
     */
    public function removeDocumentFromIndex(Document $document): void
    {
        try {
            // 使用 Scout 的 unsearchable 方法移除索引
            $document->unsearchable();

            Log::info('文档索引移除成功', [
                'document_id' => $document->id,
                'title' => $document->title,
            ]);
        } catch (\Exception $e) {
            Log::error('文档索引移除失败', [
                'document_id' => $document->id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            // 索引移除失败不影响文档的正常删除，只记录错误
        }
    }
}
