<?php

namespace App\Http\Controllers;

use App\Models\Organization;
use App\Models\VotingProcedure;
use App\Models\ElectionCycle;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;

/**
 * VotingProcedureController
 *
 * Handles CRUD operations for voting procedures.
 * Only accessible by users with Super Manager or Manager roles.
 */
class VotingProcedureController extends Controller
{
    /**
     * Display a listing of voting procedures.
     */
    public function index(): View
    {
        abort_unless(auth()->user()->can('view voting procedures'), 403,
            'You do not have permission to view voting procedures.');

        $votingProcedures = VotingProcedure::with(['organization', 'electionCycles'])
            ->withCount('electionCycles')
            ->orderBy('organization_id')
            ->orderBy('name')
            ->paginate(15);

        return view('organization.voting-procedures.index', compact('votingProcedures'));
    }

    /**
     * Show the form for creating a new voting procedure.
     */
    public function create(): View
    {
        abort_unless(auth()->user()->can('create voting procedures'), 403,
            'You do not have permission to create voting procedures.');

        $organizations = Organization::orderBy('name')->get();
        $electionCycles = null;

        if (request()->has('organization_id')) {
            $electionCycles = ElectionCycle::where('organization_id', request('organization_id'))
                ->active()
                ->orderBy('name')
                ->get();
        }

        return view('organization.voting-procedures.create', compact('organizations', 'electionCycles'));
    }

    /**
     * Store a newly created voting procedure in storage.
     */
    public function store(Request $request): RedirectResponse
    {
        abort_unless(auth()->user()->can('create voting procedures'), 403,
            'You do not have permission to create voting procedures.');

        $validated = $request->validate([
            'organization_id' => 'required|exists:organizations,id',
            'name' => 'required|string|max:191',
            'description' => 'required|string',
            'voting_method' => 'required|string|max:191',
            'rules' => 'required|string',
            'election_cycle_ids' => 'nullable|array',
            'election_cycle_ids.*' => 'exists:election_cycles,id',
        ], [
            'organization_id.required' => 'Please select an organization.',
            'name.required' => 'Procedure name is required.',
            'description.required' => 'Description is required.',
            'voting_method.required' => 'Voting method is required.',
            'rules.required' => 'Rules are required.',
        ]);

        // XSS Prevention
        $validated['name'] = strip_tags($validated['name']);
        $validated['voting_method'] = strip_tags($validated['voting_method']);

        // Create voting procedure
        $votingProcedure = VotingProcedure::create([
            'organization_id' => $validated['organization_id'],
            'name' => $validated['name'],
            'description' => $validated['description'],
            'voting_method' => $validated['voting_method'],
            'rules' => $validated['rules'],
            'version' => 1,
        ]);

        // Sync election cycles
        if (!empty($validated['election_cycle_ids'])) {
            $votingProcedure->electionCycles()->sync($validated['election_cycle_ids']);
        }

        return redirect()
            ->route('organization.voting-procedures.index')
            ->with('success', 'Voting procedure created successfully!');
    }

    /**
     * Display the specified voting procedure.
     */
    public function show(VotingProcedure $votingProcedure): View
    {
        abort_unless(auth()->user()->can('view voting procedures'), 403,
            'You do not have permission to view voting procedures.');

        $votingProcedure->load(['organization', 'electionCycles']);
        $activeElectionCycles = $votingProcedure->electionCycles()->active()->count();

        return view('organization.voting-procedures.show', compact('votingProcedure', 'activeElectionCycles'));
    }

    /**
     * Show the form for editing the specified voting procedure.
     */
    public function edit(VotingProcedure $votingProcedure): View
    {
        abort_unless(auth()->user()->can('edit voting procedures'), 403,
            'You do not have permission to edit voting procedures.');

        $organizations = Organization::orderBy('name')->get();
        $electionCycles = ElectionCycle::where('organization_id', $votingProcedure->organization_id)
            ->orderBy('name')
            ->get();
        $selectedCycles = $votingProcedure->electionCycles->pluck('id')->toArray();

        return view('organization.voting-procedures.edit', compact('votingProcedure', 'organizations', 'electionCycles', 'selectedCycles'));
    }

    /**
     * Update the specified voting procedure in storage.
     * Note: Updating increments the version number.
     */
    public function update(Request $request, VotingProcedure $votingProcedure): RedirectResponse
    {
        abort_unless(auth()->user()->can('edit voting procedures'), 403,
            'You do not have permission to edit voting procedures.');

        $validated = $request->validate([
            'organization_id' => 'required|exists:organizations,id',
            'name' => 'required|string|max:191',
            'description' => 'required|string',
            'voting_method' => 'required|string|max:191',
            'rules' => 'required|string',
            'election_cycle_ids' => 'nullable|array',
            'election_cycle_ids.*' => 'exists:election_cycles,id',
        ], [
            'organization_id.required' => 'Please select an organization.',
            'name.required' => 'Procedure name is required.',
            'description.required' => 'Description is required.',
            'voting_method.required' => 'Voting method is required.',
            'rules.required' => 'Rules are required.',
        ]);

        // XSS Prevention
        $validated['name'] = strip_tags($validated['name']);
        $validated['voting_method'] = strip_tags($validated['voting_method']);

        // Update voting procedure (version will auto-increment via model event)
        $votingProcedure->update([
            'organization_id' => $validated['organization_id'],
            'name' => $validated['name'],
            'description' => $validated['description'],
            'voting_method' => $validated['voting_method'],
            'rules' => $validated['rules'],
        ]);

        // Sync election cycles
        $votingProcedure->electionCycles()->sync($validated['election_cycle_ids'] ?? []);

        return redirect()
            ->route('organization.voting-procedures.index')
            ->with('success', 'Voting procedure updated successfully! Version is now ' . $votingProcedure->fresh()->version);
    }

    /**
     * Remove the specified voting procedure from storage.
     */
    public function destroy(VotingProcedure $votingProcedure): RedirectResponse
    {
        abort_unless(auth()->user()->can('delete voting procedures'), 403,
            'You do not have permission to delete voting procedures.');

        // Check for active election cycles
        if ($votingProcedure->hasActiveElectionCycles()) {
            return redirect()
                ->route('organization.voting-procedures.index')
                ->with('error', 'Cannot delete voting procedure associated with active election cycles.');
        }

        // Detach election cycles
        $votingProcedure->electionCycles()->detach();

        $votingProcedure->delete();

        return redirect()
            ->route('organization.voting-procedures.index')
            ->with('success', 'Voting procedure deleted successfully!');
    }

    /**
     * Get election cycles for a specific organization (AJAX).
     */
    public function getElectionCycles(Organization $organization)
    {
        $electionCycles = ElectionCycle::where('organization_id', $organization->id)
            ->active()
            ->orderBy('name')
            ->get(['id', 'name', 'start_date', 'end_date']);

        return response()->json($electionCycles);
    }
}
