<?php

namespace App\Services;

use App\Models\RPoll;
use App\Models\RPollOption;
use App\Models\RPollResponse;
use Illuminate\Support\Facades\DB;

/**
 * Service: PollService
 * 
 * Handles poll creation, voting, and results management.
 * Uses Alpine.js for real-time frontend updates.
 * 
 * @author SSHIA Development Team
 * @version 1.0.0
 */
class PollService
{
    /**
     * Create a new poll with options.
     */
    public function createPoll(array $data, int $userId): RPoll
    {
        return DB::transaction(function () use ($data, $userId) {
            // Create poll
            $poll = RPoll::create([
                'user_id' => $userId,
                'campaign_id' => $data['campaign_id'] ?? null,
                'question' => $data['question'],
                'description' => $data['description'] ?? null,
                'poll_type' => $data['poll_type'] ?? RPoll::TYPE_SINGLE,
                'max_selections' => $data['max_selections'] ?? 1,
                'allow_other' => $data['allow_other'] ?? false,
                'show_results' => $data['show_results'] ?? true,
                'results_public' => $data['results_public'] ?? true,
                'starts_at' => $data['starts_at'] ?? null,
                'ends_at' => $data['ends_at'] ?? null,
                'status' => $data['status'] ?? RPoll::STATUS_DRAFT,
                'display_position' => $data['display_position'] ?? RPoll::POSITION_SIDEBAR,
            ]);

            // Create options
            $options = $data['options'] ?? [];
            foreach ($options as $index => $optionText) {
                RPollOption::create([
                    'poll_id' => $poll->id,
                    'option_text' => $optionText,
                    'sort_order' => $index,
                ]);
            }

            // Add "Other" option if enabled
            if ($data['allow_other'] ?? false) {
                RPollOption::create([
                    'poll_id' => $poll->id,
                    'option_text' => 'Other',
                    'sort_order' => count($options),
                    'is_other' => true,
                ]);
            }

            return $poll->load('options');
        });
    }

    /**
     * Submit a vote.
     */
    public function submitVote(RPoll $poll, array $data, ?int $userId = null, ?string $respondentHash = null): RPollResponse|array
    {
        if (!$poll->isCurrentlyActive()) {
            throw new \Exception('This poll is not currently active.');
        }

        // Check if already voted
        if ($poll->hasVoted($userId, $respondentHash)) {
            throw new \Exception('You have already voted in this poll.');
        }

        // Validate selections — prefer option_ids if non-empty, otherwise wrap single option_id
        $optionIds = (!empty($data['option_ids'])) ? $data['option_ids'] : [$data['option_id']];
        $this->validateSelections($poll, $optionIds);

        return DB::transaction(function () use ($poll, $data, $optionIds, $userId, $respondentHash) {
            $responses = [];

            foreach ($optionIds as $optionId) {
                $option = RPollOption::findOrFail($optionId);

                // Create response
                $response = RPollResponse::create([
                    'poll_id' => $poll->id,
                    'option_id' => $optionId,
                    'user_id' => $userId,
                    'respondent_hash' => $respondentHash,
                    'other_text' => $option->is_other ? ($data['other_text'] ?? null) : null,
                    'ip_address' => request()->ip(),
                    'user_agent' => request()->userAgent(),
                ]);

                // Increment option vote count
                $option->incrementVote();

                $responses[] = $response;
            }

            // Update poll response count
            $poll->updateResponseCount();

            return $poll->isMultipleChoice() ? $responses : $responses[0];
        });
    }

    /**
     * Validate vote selections.
     */
    protected function validateSelections(RPoll $poll, array $optionIds): void
    {
        // Check all options belong to this poll
        $validOptions = RPollOption::where('poll_id', $poll->id)
                                   ->whereIn('id', $optionIds)
                                   ->count();

        if ($validOptions !== count($optionIds)) {
            throw new \InvalidArgumentException('Invalid option selected.');
        }

        // Check max selections for multiple choice
        if ($poll->isMultipleChoice() && count($optionIds) > $poll->max_selections) {
            throw new \InvalidArgumentException("You can select at most {$poll->max_selections} options.");
        }

        // Single choice should only have one selection
        if (!$poll->isMultipleChoice() && count($optionIds) > 1) {
            throw new \InvalidArgumentException('You can only select one option.');
        }
    }

    /**
     * Get poll results.
     */
    public function getResults(RPoll $poll): array
    {
        if (!$poll->results_public && !auth()->user()?->can('view poll results')) {
            throw new \Exception('Results are not publicly available.');
        }

        return [
            'poll_id' => $poll->id,
            'question' => $poll->question,
            'total_votes' => $poll->total_votes,
            'total_respondents' => $poll->total_responses,
            'options' => $poll->results,
        ];
    }

    /**
     * Get active polls for display.
     */
    public function getActivePolls(string $position = null)
    {
        $query = RPoll::active()
                     ->with('options')
                     ->orderByDesc('is_featured')
                     ->orderByDesc('created_at');

        if ($position) {
            $query->byPosition($position);
        }

        return $query->get();
    }

    /**
     * Get featured poll.
     */
    public function getFeaturedPoll(): ?RPoll
    {
        return RPoll::active()
                   ->featured()
                   ->with('options')
                   ->first();
    }

    /**
     * Generate respondent hash for guests.
     */
    public function generateRespondentHash(): string
    {
        return hash('sha256', request()->ip() . request()->userAgent());
    }

    /**
     * Update poll status.
     */
    public function updateStatus(RPoll $poll): void
    {
        // Auto-close expired polls
        if ($poll->status === RPoll::STATUS_ACTIVE && 
            $poll->ends_at && 
            $poll->ends_at->isPast()) {
            $poll->close();
        }

        // Auto-activate scheduled polls
        if ($poll->status === RPoll::STATUS_DRAFT &&
            $poll->starts_at &&
            $poll->starts_at->isPast()) {
            $poll->update(['status' => RPoll::STATUS_ACTIVE]);
        }
    }

    /**
     * Get poll statistics for dashboard.
     */
    public function getPollStats(): array
    {
        return [
            'total_polls' => RPoll::count(),
            'active_polls' => RPoll::active()->count(),
            'draft_polls' => RPoll::where('status', RPoll::STATUS_DRAFT)->count(),
            'closed_polls' => RPoll::where('status', RPoll::STATUS_CLOSED)->count(),
            'total_responses' => RPollResponse::count(),
        ];
    }
}
