<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;

/**
 * Model: RPoll (Community Poll)
 * 
 * Represents a polling question for community sentiment and feedback.
 * Supports single-choice and multiple-choice polls with real-time results.
 * 
 * @property int $id
 * @property int|null $campaign_id
 * @property int $user_id
 * @property string $question
 * @property string|null $description
 * @property string $poll_type
 * @property int $max_selections
 * @property bool $allow_other
 * @property bool $show_results
 * @property bool $results_public
 * @property \Carbon\Carbon|null $starts_at
 * @property \Carbon\Carbon|null $ends_at
 * @property string $status
 * @property bool $is_featured
 * @property string $display_position
 * @property int $total_responses
 */
class RPoll extends Model
{
    use HasFactory, SoftDeletes;

    protected $table = 'r_polls';

    protected $fillable = [
        'campaign_id',
        'user_id',
        'question',
        'description',
        'poll_type',
        'max_selections',
        'allow_other',
        'show_results',
        'results_public',
        'starts_at',
        'ends_at',
        'status',
        'is_featured',
        'display_position',
        'total_responses',
    ];

    protected $casts = [
        'max_selections' => 'integer',
        'allow_other' => 'boolean',
        'show_results' => 'boolean',
        'results_public' => 'boolean',
        'is_featured' => 'boolean',
        'starts_at' => 'datetime',
        'ends_at' => 'datetime',
        'total_responses' => 'integer',
    ];

    /**
     * Poll type constants.
     */
    const TYPE_SINGLE = 'single_choice';
    const TYPE_MULTIPLE = 'multiple_choice';

    /**
     * Status constants.
     */
    const STATUS_DRAFT = 'draft';
    const STATUS_ACTIVE = 'active';
    const STATUS_CLOSED = 'closed';
    const STATUS_ARCHIVED = 'archived';

    /**
     * Display position constants.
     */
    const POSITION_SIDEBAR = 'sidebar';
    const POSITION_INLINE = 'inline';
    const POSITION_MODAL = 'modal';

    /**
     * Get the campaign this poll belongs to.
     */
    public function campaign(): BelongsTo
    {
        return $this->belongsTo(RCampaign::class, 'campaign_id');
    }

    /**
     * Get the poll creator.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    /**
     * Get all options for this poll.
     */
    public function options(): HasMany
    {
        return $this->hasMany(RPollOption::class, 'poll_id')->orderBy('sort_order');
    }

    /**
     * Get all responses for this poll.
     */
    public function responses(): HasMany
    {
        return $this->hasMany(RPollResponse::class, 'poll_id');
    }

    /**
     * Scope: Active polls.
     */
    public function scopeActive($query)
    {
        return $query->where('status', self::STATUS_ACTIVE)
                     ->where(function ($q) {
                         $q->whereNull('starts_at')
                           ->orWhere('starts_at', '<=', now());
                     })
                     ->where(function ($q) {
                         $q->whereNull('ends_at')
                           ->orWhere('ends_at', '>=', now());
                     });
    }

    /**
     * Scope: Featured polls.
     */
    public function scopeFeatured($query)
    {
        return $query->where('is_featured', true);
    }

    /**
     * Scope: By display position.
     */
    public function scopeByPosition($query, string $position)
    {
        return $query->where('display_position', $position);
    }

    /**
     * Check if poll is currently active.
     */
    public function isCurrentlyActive(): bool
    {
        if ($this->status !== self::STATUS_ACTIVE) {
            return false;
        }

        if ($this->starts_at && $this->starts_at->isFuture()) {
            return false;
        }

        if ($this->ends_at && $this->ends_at->isPast()) {
            return false;
        }

        return true;
    }

    /**
     * Check if user has already voted.
     */
    public function hasVoted(?int $userId, ?string $respondentHash): bool
    {
        if ($userId) {
            return $this->responses()->where('user_id', $userId)->exists();
        }

        if ($respondentHash) {
            return $this->responses()->where('respondent_hash', $respondentHash)->exists();
        }

        return false;
    }

    /**
     * Check if poll allows multiple selections.
     */
    public function isMultipleChoice(): bool
    {
        return $this->poll_type === self::TYPE_MULTIPLE;
    }

    /**
     * Get total votes across all options.
     */
    public function getTotalVotesAttribute(): int
    {
        return $this->options()->sum('votes_count');
    }

    /**
     * Get results with percentages.
     */
    public function getResultsAttribute(): array
    {
        $total = $this->total_votes;
        $options = $this->options;

        return $options->map(function ($option) use ($total) {
            $percentage = $total > 0 ? round(($option->votes_count / $total) * 100, 1) : 0;
            
            return [
                'id' => $option->id,
                'text' => $option->option_text,
                'votes' => $option->votes_count,
                'percentage' => $percentage,
                'color' => $option->color,
            ];
        })->toArray();
    }

    /**
     * Update total responses count.
     */
    public function updateResponseCount(): void
    {
        $this->total_responses = $this->responses()->count();
        $this->save();
    }

    /**
     * Close the poll.
     */
    public function close(): void
    {
        $this->update(['status' => self::STATUS_CLOSED]);
    }

    /**
     * Get status color for UI.
     */
    public function getStatusColorAttribute(): string
    {
        return match($this->status) {
            self::STATUS_DRAFT => 'gray',
            self::STATUS_ACTIVE => 'green',
            self::STATUS_CLOSED => 'blue',
            self::STATUS_ARCHIVED => 'red',
            default => 'gray',
        };
    }
}
