<?php

namespace App\Services;

use App\Models\Discussion;
use App\Models\DiscussionTopic;
use App\Models\DiscussionReply;
use App\Models\User;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

/**
 * DiscussionService
 * 
 * Handles all business logic for the Discussion Boards module.
 * Provides methods for creating, updating, and managing discussions and replies.
 * 
 * @package App\Services
 */
class DiscussionService
{
    /**
     * Create a new discussion.
     *
     * @param array $data Discussion data
     * @param \App\Models\User $user The user creating the discussion
     * @return \App\Models\Discussion
     */
    public function createDiscussion(array $data, User $user): Discussion
    {
        return DB::transaction(function () use ($data, $user) {
            // XSS Prevention - strip tags from user input
            $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;
            $data['last_activity_at'] = now();

            // Set default status
            if (!isset($data['status'])) {
                $data['status'] = Discussion::STATUS_PUBLISHED;
            }

            // Generate slug if not provided
            if (empty($data['slug'])) {
                $data['slug'] = Discussion::generateUniqueSlug($data['title']);
            }

            $discussion = Discussion::create($data);

            return $discussion;
        });
    }

    /**
     * Update an existing discussion.
     *
     * @param \App\Models\Discussion $discussion
     * @param array $data
     * @return \App\Models\Discussion
     */
    public function updateDiscussion(Discussion $discussion, array $data): Discussion
    {
        return DB::transaction(function () use ($discussion, $data) {
            // XSS Prevention
            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);
            }

            $discussion->update($data);

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

    /**
     * Delete a discussion.
     *
     * @param \App\Models\Discussion $discussion
     * @return bool
     */
    public function deleteDiscussion(Discussion $discussion): bool
    {
        return DB::transaction(function () use ($discussion) {
            // Soft delete the discussion
            return $discussion->delete();
        });
    }

    /**
     * Get public discussions with filtering and pagination.
     *
     * @param array $filters
     * @param int $perPage
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function getPublicDiscussions(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = Discussion::query()
            ->with(['user', 'topic', 'lastReplyUser'])
            ->published()
            ->withCount('activeReplies');

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

        // Apply topic slug filter
        if (!empty($filters['topic_slug'])) {
            $topic = DiscussionTopic::where('slug', $filters['topic_slug'])->first();
            if ($topic) {
                $query->where('topic_id', $topic->id);
            }
        }

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

        // Apply sorting
        $sort = $filters['sort'] ?? 'latest';
        switch ($sort) {
            case 'popular':
                $query->popular();
                break;
            case 'active':
                $query->latestActivity();
                break;
            case 'featured':
                $query->featured()->latestActivity();
                break;
            default:
                // Pinned first, then by latest activity
                $query->orderByDesc('is_pinned')->latestActivity();
        }

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

    /**
     * Get a discussion by slug for public viewing.
     *
     * @param string $slug
     * @return \App\Models\Discussion|null
     */
    public function getDiscussionBySlug(string $slug): ?Discussion
    {
        return Discussion::with(['user', 'topic'])
            ->where('slug', $slug)
            ->published()
            ->firstOrFail();
    }

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

    /**
     * Create a reply to a discussion.
     *
     * @param \App\Models\Discussion $discussion
     * @param array $data
     * @param \App\Models\User $user
     * @return \App\Models\DiscussionReply
     */
    public function createReply(Discussion $discussion, array $data, User $user): DiscussionReply
    {
        return DB::transaction(function () use ($discussion, $data, $user) {
            // XSS Prevention
            $data['content'] = $this->sanitizeContent($data['content']);
            $data['discussion_id'] = $discussion->id;
            $data['user_id'] = $user->id;

            // Handle parent reply for threaded replies
            if (!empty($data['parent_id'])) {
                $parent = DiscussionReply::find($data['parent_id']);
                if ($parent && $parent->discussion_id === $discussion->id) {
                    $data['depth'] = min($parent->depth + 1, DiscussionReply::MAX_DEPTH);
                } else {
                    unset($data['parent_id']);
                }
            }

            $reply = DiscussionReply::create($data);

            return $reply;
        });
    }

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

            $reply->update($data);

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

    /**
     * Delete a reply.
     *
     * @param \App\Models\DiscussionReply $reply
     * @return bool
     */
    public function deleteReply(DiscussionReply $reply): bool
    {
        return DB::transaction(function () use ($reply) {
            $discussion = $reply->discussion;
            $deleted = $reply->delete();

            if ($deleted) {
                $discussion->updateReplyStats();
            }

            return $deleted;
        });
    }

    /**
     * Get replies for a discussion with pagination.
     *
     * @param \App\Models\Discussion $discussion
     * @param int $perPage
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function getDiscussionReplies(Discussion $discussion, int $perPage = 10): LengthAwarePaginator
    {
        return $discussion->topLevelReplies()
            ->with(['user', 'activeReplies.user', 'activeReplies.activeReplies.user'])
            ->orderByDesc('is_accepted_answer')
            ->orderBy('created_at')
            ->paginate($perPage);
    }

    /**
     * Accept a reply as the answer.
     *
     * @param \App\Models\DiscussionReply $reply
     * @return void
     */
    public function acceptAnswer(DiscussionReply $reply): void
    {
        $reply->markAsAccepted();
    }

    /**
     * Get featured discussions.
     *
     * @param int $limit
     * @return \Illuminate\Support\Collection
     */
    public function getFeaturedDiscussions(int $limit = 5): Collection
    {
        return Discussion::with(['user', 'topic'])
            ->published()
            ->featured()
            ->latestActivity()
            ->limit($limit)
            ->get();
    }

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

    /**
     * Get discussion statistics.
     *
     * @return array
     */
    public function getStatistics(): array
    {
        return [
            'total_discussions' => Discussion::count(),
            'published_discussions' => Discussion::published()->count(),
            'total_topics' => DiscussionTopic::active()->count(),
            'total_replies' => DiscussionReply::active()->count(),
            'featured_discussions' => Discussion::published()->featured()->count(),
            'recent_discussions' => Discussion::published()
                ->where('created_at', '>=', now()->subDays(7))
                ->count(),
            'total_contributors' => User::whereHas('discussions')->count(),
        ];
    }

    /**
     * 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>';
        
        // 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;
    }

    /**
     * Get all active topics with discussion counts.
     *
     * @return \Illuminate\Support\Collection
     */
    public function getActiveTopics(): Collection
    {
        return DiscussionTopic::active()
            ->ordered()
            ->withCount(['discussions' => function ($query) {
                $query->published();
            }])
            ->get();
    }

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

    /**
     * Create a new topic.
     *
     * @param array $data
     * @return \App\Models\DiscussionTopic
     */
    public function createTopic(array $data): DiscussionTopic
    {
        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'] = DiscussionTopic::generateUniqueSlug($data['name']);
            }

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

    /**
     * Update a topic.
     *
     * @param \App\Models\DiscussionTopic $topic
     * @param array $data
     * @return \App\Models\DiscussionTopic
     */
    public function updateTopic(DiscussionTopic $topic, array $data): DiscussionTopic
    {
        return DB::transaction(function () use ($topic, $data) {
            if (isset($data['name'])) {
                $data['name'] = strip_tags($data['name']);
            }
            if (isset($data['description'])) {
                $data['description'] = strip_tags($data['description']);
            }

            $topic->update($data);

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

    /**
     * Delete a topic.
     *
     * @param \App\Models\DiscussionTopic $topic
     * @return bool
     */
    public function deleteTopic(DiscussionTopic $topic): bool
    {
        return $topic->delete();
    }

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

    /**
     * Toggle pinned status for a discussion.
     *
     * @param \App\Models\Discussion $discussion
     * @return bool
     */
    public function togglePinned(Discussion $discussion): bool
    {
        $discussion->is_pinned = !$discussion->is_pinned;
        $discussion->save();
        
        return $discussion->is_pinned;
    }
}
