<?php

namespace App\Http\Controllers\Advocacy;

use App\Http\Controllers\Controller;
use App\Models\RPoll;
use App\Services\PollService;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Http\JsonResponse;

/**
 * Controller: RPollController
 * 
 * Handles poll management and AJAX voting functionality.
 * Uses Alpine.js for real-time frontend updates.
 * 
 * @author SSHIA Development Team
 * @version 1.0.0
 */
class RPollController extends Controller
{
    /**
     * Create a new controller instance.
     */
    public function __construct(
        protected PollService $pollService
    ) {}

    /**
     * Display poll management index.
     */
    public function index(Request $request): View
    {
        abort_unless(auth()->user()->can('view polls'), 403);

        $query = RPoll::with(['user', 'campaign', 'options'])
                      ->orderByDesc('created_at');

        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        $polls = $query->paginate(15);

        $stats = $this->pollService->getPollStats();

        return view('advocacy.polls.index', [
            'polls' => $polls,
            'stats' => $stats,
            'filters' => $request->only(['status']),
        ]);
    }

    /**
     * Show form for creating poll.
     */
    public function create(): View
    {
        abort_unless(auth()->user()->can('create polls'), 403);

        $campaigns = \App\Models\RCampaign::active()
            ->orderBy('title')
            ->get(['id', 'title']);

        return view('advocacy.polls.create', [
            'campaigns' => $campaigns,
        ]);
    }

    /**
     * Store new poll.
     */
    public function store(Request $request): mixed
    {
        abort_unless(auth()->user()->can('create polls'), 403);

        $validated = $request->validate([
            'question' => 'required|string|max:500',
            'description' => 'nullable|string|max:2000',
            'campaign_id' => 'nullable|exists:r_campaigns,id',
            'poll_type' => 'required|in:single_choice,multiple_choice',
            'max_selections' => 'nullable|integer|min:1|max:10',
            'allow_other' => 'nullable|boolean',
            'show_results' => 'nullable|boolean',
            'results_public' => 'nullable|boolean',
            'starts_at' => 'nullable|date',
            'ends_at' => 'nullable|date|after:starts_at',
            'status' => 'required|in:draft,active',
            'display_position' => 'nullable|in:sidebar,inline,modal',
            'options' => 'required|array|min:2|max:10',
            'options.*' => 'required|string|max:500',
        ]);

        try {
            $poll = $this->pollService->createPoll($validated, auth()->id());

            return redirect()
                ->route('advocacy.polls.index')
                ->with('success', 'Poll created successfully!');

        } catch (\Exception $e) {
            return back()
                ->withInput()
                ->with('error', 'Failed to create poll: ' . $e->getMessage());
        }
    }

    /**
     * Display poll details.
     */
    public function show(RPoll $poll): View
    {
        abort_unless(auth()->user()->can('view polls'), 403);

        $poll->load(['options', 'campaign', 'responses.user']);

        $resultsData = $this->pollService->getResults($poll);

        return view('advocacy.polls.show', [
            'poll'    => $poll,
            'results' => $resultsData['options'], // flat array of ['id','text','votes','percentage','color']
        ]);
    }

    /**
     * Show form for editing poll.
     */
    public function edit(RPoll $poll): View
    {
        abort_unless(auth()->user()->can('edit polls'), 403);

        // Can only edit draft polls
        if ($poll->status !== RPoll::STATUS_DRAFT) {
            return redirect()
                ->route('advocacy.polls.show', $poll)
                ->with('error', 'Only draft polls can be edited.');
        }

        $campaigns = \App\Models\RCampaign::active()
            ->orderBy('title')
            ->get(['id', 'title']);

        return view('advocacy.polls.edit', [
            'poll' => $poll->load('options'),
            'campaigns' => $campaigns,
        ]);
    }

    /**
     * Update poll.
     */
    public function update(Request $request, RPoll $poll): mixed
    {
        abort_unless(auth()->user()->can('edit polls'), 403);

        if ($poll->status !== RPoll::STATUS_DRAFT) {
            return back()->with('error', 'Only draft polls can be edited.');
        }

        $validated = $request->validate([
            'question' => 'required|string|max:500',
            'description' => 'nullable|string|max:2000',
            'campaign_id' => 'nullable|exists:r_campaigns,id',
            'poll_type' => 'required|in:single_choice,multiple_choice',
            'max_selections' => 'nullable|integer|min:1|max:10',
            'allow_other' => 'nullable|boolean',
            'show_results' => 'nullable|boolean',
            'results_public' => 'nullable|boolean',
            'starts_at' => 'nullable|date',
            'ends_at' => 'nullable|date|after:starts_at',
            'status' => 'required|in:draft,active',
            'display_position' => 'nullable|in:sidebar,inline,modal',
            'options' => 'required|array|min:2|max:10',
            'options.*.id' => 'nullable|exists:r_poll_options,id',
            'options.*.option_text' => 'required|string|max:500',
        ]);

        try {
            $poll->update($validated);

            // Update options
            foreach ($validated['options'] as $index => $optionData) {
                if (!empty($optionData['id'])) {
                    $poll->options()
                        ->where('id', $optionData['id'])
                        ->update([
                            'option_text' => $optionData['option_text'],
                            'sort_order' => $index,
                        ]);
                } else {
                    $poll->options()->create([
                        'option_text' => $optionData['option_text'],
                        'sort_order' => $index,
                    ]);
                }
            }

            return redirect()
                ->route('advocacy.polls.show', $poll)
                ->with('success', 'Poll updated successfully!');

        } catch (\Exception $e) {
            return back()
                ->withInput()
                ->with('error', 'Failed to update poll: ' . $e->getMessage());
        }
    }

    /**
     * Delete poll.
     */
    public function destroy(RPoll $poll): mixed
    {
        abort_unless(auth()->user()->can('delete polls'), 403);

        $poll->delete();

        return redirect()
            ->route('advocacy.polls.index')
            ->with('success', 'Poll deleted successfully!');
    }

    /**
     * Submit vote (AJAX).
     * Public access.
     */
    public function vote(Request $request, RPoll $poll): JsonResponse
    {
        try {
            $validated = $request->validate([
                'option_id' => 'required_without:option_ids|exists:r_poll_options,id',
                'option_ids' => 'required_without:option_id|array',
                'option_ids.*' => 'exists:r_poll_options,id',
                'other_text' => 'nullable|string|max:500',
            ]);

            // Get user or generate guest hash
            $userId = auth()->id();
            $respondentHash = $userId ? null : $this->pollService->generateRespondentHash();

            // Check if already voted
            if ($poll->hasVoted($userId, $respondentHash)) {
                return response()->json([
                    'success' => false,
                    'message' => 'You have already voted in this poll.',
                ], 400);
            }

            // Submit vote
            $data = [
                'option_id' => $validated['option_id'] ?? null,
                'option_ids' => $validated['option_ids'] ?? [],
                'other_text' => $validated['other_text'] ?? null,
            ];

            $response = $this->pollService->submitVote(
                $poll,
                $data,
                $userId,
                $respondentHash
            );

            // Return updated results — reload poll to get fresh vote counts
            $poll->refresh();
            $results = $this->pollService->getResults($poll);

            return response()->json([
                'success' => true,
                'message' => 'Thank you for voting!',
                'results' => $results['options'],  // flat array of {id, text, votes, percentage}
                'total_votes' => $results['total_votes'],
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Get poll results (AJAX).
     */
    public function results(RPoll $poll): JsonResponse
    {
        try {
            $results = $this->pollService->getResults($poll);

            return response()->json([
                'success' => true,
                'data' => $results,
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Get active polls — returns HTML view for browser requests, JSON for AJAX.
     */
    public function active(Request $request): mixed
    {
        $position = $request->input('position', 'sidebar');
        $polls = $this->pollService->getActivePolls($position);

        if ($request->expectsJson()) {
            return response()->json([
                'success' => true,
                'data' => $polls,
            ]);
        }

        return view('advocacy.polls.active', ['polls' => $polls]);
    }

    /**
     * Close poll.
     */
    public function close(RPoll $poll): JsonResponse
    {
        abort_unless(auth()->user()->can('edit polls'), 403);

        $poll->close();

        return response()->json([
            'success' => true,
            'message' => 'Poll closed successfully.',
        ]);
    }
}
