<?php

namespace App\Services;

use App\Models\KnowledgeBaseCategory;
use App\Models\KnowledgeBaseQuestion;
use App\Models\KnowledgeBaseAnswer;
use App\Models\User;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

/**
 * KnowledgeBaseService
 * 
 * Handles all business logic for the Knowledge Base module.
 * Provides methods for managing categories, questions, and answers.
 * 
 * @package App\Services
 */
class KnowledgeBaseService
{
    /**
     * Create a new category.
     *
     * @param array $data
     * @return \App\Models\KnowledgeBaseCategory
     */
    public function createCategory(array $data): KnowledgeBaseCategory
    {
        return DB::transaction(function () use ($data) {
            // XSS Prevention
            $data['name'] = strip_tags($data['name']);
            $data['description'] = strip_tags($data['description'] ?? '');

            if (empty($data['slug'])) {
                $data['slug'] = KnowledgeBaseCategory::generateUniqueSlug($data['name']);
            }

            return KnowledgeBaseCategory::create($data);
        });
    }

    /**
     * Update an existing category.
     *
     * @param \App\Models\KnowledgeBaseCategory $category
     * @param array $data
     * @return \App\Models\KnowledgeBaseCategory
     */
    public function updateCategory(KnowledgeBaseCategory $category, array $data): KnowledgeBaseCategory
    {
        return DB::transaction(function () use ($category, $data) {
            if (isset($data['name'])) {
                $data['name'] = strip_tags($data['name']);
            }
            if (isset($data['description'])) {
                $data['description'] = strip_tags($data['description']);
            }

            $category->update($data);

            return $category->fresh();
        });
    }

    /**
     * Delete a category.
     *
     * @param \App\Models\KnowledgeBaseCategory $category
     * @return bool
     */
    public function deleteCategory(KnowledgeBaseCategory $category): bool
    {
        return DB::transaction(function () use ($category) {
            return $category->delete();
        });
    }

    /**
     * Get all active categories with question counts.
     *
     * @return \Illuminate\Support\Collection
     */
    public function getActiveCategories(): Collection
    {
        return KnowledgeBaseCategory::active()
            ->with(['children' => function ($query) {
                $query->active()->orderBy('sort_order');
            }])
            ->withCount(['questions' => function ($query) {
                $query->published();
            }])
            ->root()
            ->ordered()
            ->get();
    }

    /**
     * Get category by slug.
     *
     * @param string $slug
     * @return \App\Models\KnowledgeBaseCategory|null
     */
    public function getCategoryBySlug(string $slug): ?KnowledgeBaseCategory
    {
        return KnowledgeBaseCategory::active()
            ->where('slug', $slug)
            ->firstOrFail();
    }

    /**
     * Create a new question.
     *
     * @param array $data
     * @param \App\Models\User $user
     * @return \App\Models\KnowledgeBaseQuestion
     */
    public function createQuestion(array $data, User $user): KnowledgeBaseQuestion
    {
        return DB::transaction(function () use ($data, $user) {
            // XSS Prevention
            $data['title'] = strip_tags($data['title']);
            $data['content'] = $this->sanitizeContent($data['content'] ?? '');
            $data['excerpt'] = Str::limit(strip_tags($data['content']), 200);
            $data['user_id'] = $user->id;

            // Set default status
            if (!isset($data['status'])) {
                $data['status'] = KnowledgeBaseQuestion::STATUS_DRAFT;
                $data['is_published'] = false;
            }

            // Handle tags
            if (isset($data['tags']) && is_string($data['tags'])) {
                $data['tags'] = array_map('trim', explode(',', $data['tags']));
            }

            $question = KnowledgeBaseQuestion::create($data);

            return $question;
        });
    }

    /**
     * Update an existing question.
     *
     * @param \App\Models\KnowledgeBaseQuestion $question
     * @param array $data
     * @return \App\Models\KnowledgeBaseQuestion
     */
    public function updateQuestion(KnowledgeBaseQuestion $question, array $data): KnowledgeBaseQuestion
    {
        return DB::transaction(function () use ($question, $data) {
            if (isset($data['title'])) {
                $data['title'] = strip_tags($data['title']);
            }
            if (isset($data['content'])) {
                $data['content'] = $this->sanitizeContent($data['content']);
                $data['excerpt'] = Str::limit(strip_tags($data['content']), 200);
            }

            // Handle tags
            if (isset($data['tags']) && is_string($data['tags'])) {
                $data['tags'] = array_map('trim', explode(',', $data['tags']));
            }

            $oldCategoryId = $question->category_id;
            $question->update($data);

            // Update category counts if changed
            if (isset($data['category_id']) && $data['category_id'] != $oldCategoryId) {
                $oldCategory = KnowledgeBaseCategory::find($oldCategoryId);
                $oldCategory?->updateQuestionsCount();
                $question->category?->updateQuestionsCount();
            }

            return $question->fresh();
        });
    }

    /**
     * Publish a question.
     *
     * @param \App\Models\KnowledgeBaseQuestion $question
     * @return \App\Models\KnowledgeBaseQuestion
     */
    public function publishQuestion(KnowledgeBaseQuestion $question): KnowledgeBaseQuestion
    {
        return DB::transaction(function () use ($question) {
            $question->publish();
            return $question->fresh();
        });
    }

    /**
     * Archive a question.
     *
     * @param \App\Models\KnowledgeBaseQuestion $question
     * @return \App\Models\KnowledgeBaseQuestion
     */
    public function archiveQuestion(KnowledgeBaseQuestion $question): KnowledgeBaseQuestion
    {
        return DB::transaction(function () use ($question) {
            $question->archive();
            return $question->fresh();
        });
    }

    /**
     * Delete a question.
     *
     * @param \App\Models\KnowledgeBaseQuestion $question
     * @return bool
     */
    public function deleteQuestion(KnowledgeBaseQuestion $question): bool
    {
        return DB::transaction(function () use ($question) {
            $category = $question->category;
            $deleted = $question->delete();

            if ($deleted && $category) {
                $category->updateQuestionsCount();
            }

            return $deleted;
        });
    }

    /**
     * Get public questions with filtering and pagination.
     *
     * @param array $filters
     * @param int $perPage
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function getPublicQuestions(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = KnowledgeBaseQuestion::query()
            ->with(['category', 'user'])
            ->published();

        // Apply category filter
        if (!empty($filters['category_id'])) {
            $query->where('category_id', $filters['category_id']);
        }

        // Apply category slug filter
        if (!empty($filters['category_slug'])) {
            $category = KnowledgeBaseCategory::where('slug', $filters['category_slug'])->first();
            if ($category) {
                $query->where('category_id', $category->id);
            }
        }

        // Apply difficulty filter
        if (!empty($filters['difficulty'])) {
            $query->where('difficulty', $filters['difficulty']);
        }

        // Apply tag filter
        if (!empty($filters['tag'])) {
            $query->whereJsonContains('tags', $filters['tag']);
        }

        // Apply search filter
        if (!empty($filters['search'])) {
            $query->search($filters['search']);
        }

        // Apply sorting
        $sort = $filters['sort'] ?? 'recent';
        switch ($sort) {
            case 'popular':
                $query->popular();
                break;
            case 'helpful':
                $query->orderByDesc('helpful_count');
                break;
            case 'featured':
                $query->featured()->recent();
                break;
            default:
                $query->recent();
        }

        return $query->paginate($perPage);
    }

    /**
     * Get question by slug for public viewing.
     *
     * @param string $slug
     * @return \App\Models\KnowledgeBaseQuestion|null
     */
    public function getQuestionBySlug(string $slug): ?KnowledgeBaseQuestion
    {
        return KnowledgeBaseQuestion::with(['category', 'user', 'publishedAnswers.user'])
            ->where('slug', $slug)
            ->published()
            ->firstOrFail();
    }

    /**
     * Increment question view count.
     *
     * @param \App\Models\KnowledgeBaseQuestion $question
     * @return void
     */
    public function incrementViewCount(KnowledgeBaseQuestion $question): void
    {
        $question->incrementViewCount();
    }

    /**
     * Create an answer for a question.
     *
     * @param \App\Models\KnowledgeBaseQuestion $question
     * @param array $data
     * @param \App\Models\User $user
     * @return \App\Models\KnowledgeBaseAnswer
     */
    public function createAnswer(KnowledgeBaseQuestion $question, array $data, User $user): KnowledgeBaseAnswer
    {
        return DB::transaction(function () use ($question, $data, $user) {
            // XSS Prevention
            $data['content'] = $this->sanitizeContent($data['content']);
            $data['question_id'] = $question->id;
            $data['user_id'] = $user->id;
            $data['is_published'] = $data['is_published'] ?? true;
            $data['sort_order'] = $question->answers()->max('sort_order') + 1;

            $answer = KnowledgeBaseAnswer::create($data);

            // Update answer count
            $question->updateAnswerCount();

            return $answer;
        });
    }

    /**
     * Update an answer.
     *
     * @param \App\Models\KnowledgeBaseAnswer $answer
     * @param array $data
     * @return \App\Models\KnowledgeBaseAnswer
     */
    public function updateAnswer(KnowledgeBaseAnswer $answer, array $data): KnowledgeBaseAnswer
    {
        return DB::transaction(function () use ($answer, $data) {
            if (isset($data['content'])) {
                $data['content'] = $this->sanitizeContent($data['content']);
            }

            $answer->update($data);

            if (isset($data['is_published'])) {
                $answer->question->updateAnswerCount();
            }

            return $answer->fresh();
        });
    }

    /**
     * Delete an answer.
     *
     * @param \App\Models\KnowledgeBaseAnswer $answer
     * @return bool
     */
    public function deleteAnswer(KnowledgeBaseAnswer $answer): bool
    {
        return DB::transaction(function () use ($answer) {
            $question = $answer->question;
            $deleted = $answer->delete();

            if ($deleted) {
                $question->updateAnswerCount();
            }

            return $deleted;
        });
    }

    /**
     * Accept an answer.
     *
     * @param \App\Models\KnowledgeBaseAnswer $answer
     * @param \App\Models\User $user
     * @return void
     */
    public function acceptAnswer(KnowledgeBaseAnswer $answer, User $user): void
    {
        $answer->accept($user);
    }

    /**
     * Unaccept an answer.
     *
     * @param \App\Models\KnowledgeBaseAnswer $answer
     * @return void
     */
    public function unacceptAnswer(KnowledgeBaseAnswer $answer): void
    {
        $answer->unaccept();
    }

    /**
     * Get featured questions.
     *
     * @param int $limit
     * @return \Illuminate\Support\Collection
     */
    public function getFeaturedQuestions(int $limit = 5): Collection
    {
        return KnowledgeBaseQuestion::with(['category', 'user'])
            ->published()
            ->featured()
            ->recent()
            ->limit($limit)
            ->get();
    }

    /**
     * Get popular questions.
     *
     * @param int $limit
     * @return \Illuminate\Support\Collection
     */
    public function getPopularQuestions(int $limit = 5): Collection
    {
        return KnowledgeBaseQuestion::with(['category', 'user'])
            ->published()
            ->popular()
            ->limit($limit)
            ->get();
    }

    /**
     * Get recent questions.
     *
     * @param int $limit
     * @return \Illuminate\Support\Collection
     */
    public function getRecentQuestions(int $limit = 5): Collection
    {
        return KnowledgeBaseQuestion::with(['category', 'user'])
            ->published()
            ->recent()
            ->limit($limit)
            ->get();
    }

    /**
     * Get questions by category.
     *
     * @param \App\Models\KnowledgeBaseCategory $category
     * @param int $perPage
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function getQuestionsByCategory(KnowledgeBaseCategory $category, int $perPage = 15): LengthAwarePaginator
    {
        return KnowledgeBaseQuestion::with(['user'])
            ->published()
            ->where('category_id', $category->id)
            ->recent()
            ->paginate($perPage);
    }

    /**
     * Get knowledge base statistics.
     *
     * @return array
     */
    public function getStatistics(): array
    {
        return [
            'total_questions' => KnowledgeBaseQuestion::count(),
            'published_questions' => KnowledgeBaseQuestion::published()->count(),
            'total_categories' => KnowledgeBaseCategory::active()->count(),
            'total_answers' => KnowledgeBaseAnswer::where('is_published', true)->count(),
            'featured_questions' => KnowledgeBaseQuestion::published()->featured()->count(),
            'accepted_answers' => KnowledgeBaseAnswer::accepted()->count(),
            'recent_questions' => KnowledgeBaseQuestion::published()
                ->where('published_at', '>=', now()->subDays(7))
                ->count(),
            'total_views' => (int) KnowledgeBaseQuestion::published()->sum('view_count'),
        ];
    }

    /**
     * Get all tags with usage counts.
     *
     * @return array
     */
    public function getTagsWithCount(): array
    {
        $tags = [];
        
        KnowledgeBaseQuestion::published()
            ->whereNotNull('tags')
            ->get(['tags'])
            ->each(function ($question) use (&$tags) {
                foreach ($question->tags ?? [] as $tag) {
                    $tags[$tag] = ($tags[$tag] ?? 0) + 1;
                }
            });

        arsort($tags);
        
        return $tags;
    }

    /**
     * Sanitize content for safe display.
     *
     * @param string $content
     * @return string
     */
    protected function sanitizeContent(string $content): string
    {
        // Allow basic HTML tags for rich content
        $allowedTags = '<p><br><strong><b><em><i><u><s><a><ul><ol><li><blockquote><code><pre><h1><h2><h3><h4><h5><h6><img>';
        
        // Strip tags except allowed
        $content = strip_tags($content, $allowedTags);
        
        // Remove any potential script injections
        $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content);
        $content = preg_replace('/on\w+\s*=\s*["\'][^"\']*["\']/i', '', $content);
        
        return $content;
    }

    /**
     * Toggle featured status for a question.
     *
     * @param \App\Models\KnowledgeBaseQuestion $question
     * @return bool
     */
    public function toggleFeatured(KnowledgeBaseQuestion $question): bool
    {
        $question->is_featured = !$question->is_featured;
        $question->save();
        
        return $question->is_featured;
    }

    /**
     * Mark an answer as helpful by a user.
     *
     * @param \App\Models\KnowledgeBaseAnswer $answer
     * @param \App\Models\User $user
     * @return bool  true = marked helpful, false = already voted
     */
    public function markHelpful(KnowledgeBaseAnswer $answer, User $user): bool
    {
        $alreadyVoted = \Illuminate\Support\Facades\DB::table('answer_helpful_votes')
            ->where('answer_id', $answer->id)
            ->where('user_id', $user->id)
            ->exists();

        if ($alreadyVoted) {
            return false;
        }

        \Illuminate\Support\Facades\DB::table('answer_helpful_votes')->insert([
            'answer_id'  => $answer->id,
            'user_id'    => $user->id,
            'created_at' => now(),
        ]);

        $answer->increment('helpful_count');

        return true;
    }

    /**
     * Remove helpful vote from an answer.
     *
     * @param \App\Models\KnowledgeBaseAnswer $answer
     * @param \App\Models\User $user
     * @return bool  true = removed, false = no vote existed
     */
    public function markNotHelpful(KnowledgeBaseAnswer $answer, User $user): bool
    {
        $deleted = \Illuminate\Support\Facades\DB::table('answer_helpful_votes')
            ->where('answer_id', $answer->id)
            ->where('user_id', $user->id)
            ->delete();

        if ($deleted) {
            $answer->decrement('helpful_count');
            return true;
        }

        return false;
    }

    /**
     * Update sort order for answers.
     *
     * @param \App\Models\KnowledgeBaseQuestion $question
     * @param array $order Array of answer IDs in new order
     * @return void
     */
    public function updateAnswerOrder(KnowledgeBaseQuestion $question, array $order): void
    {
        DB::transaction(function () use ($order) {
            foreach ($order as $index => $answerId) {
                KnowledgeBaseAnswer::where('id', $answerId)
                    ->update(['sort_order' => $index]);
            }
        });
    }
}
