<?php

namespace App\Services\Elections\Strategies;

use App\Models\ElectionPosition;
use App\Services\Elections\VotingStrategyInterface;
use Illuminate\Support\Collection;

class WeightedStrategy implements VotingStrategyInterface
{
    public function validateVoteData(array $voteData, ElectionPosition $position): bool
    {
        if (!isset($voteData['weights']) || !is_array($voteData['weights'])) {
            return false;
        }

        if (empty($voteData['weights'])) {
            return false;
        }

        $approvedIds = $position->approvedCandidates()->pluck('id')->toArray();
        $totalWeight = 0;
        $candidateIds = [];

        foreach ($voteData['weights'] as $entry) {
            if (!isset($entry['candidate_id'], $entry['weight'])) {
                return false;
            }
            if (!in_array($entry['candidate_id'], $approvedIds)) {
                return false;
            }
            if (in_array($entry['candidate_id'], $candidateIds)) {
                return false; // duplicate
            }
            if (!is_numeric($entry['weight']) || $entry['weight'] < 0) {
                return false;
            }
            $candidateIds[] = $entry['candidate_id'];
            $totalWeight += $entry['weight'];
        }

        // Total weight must equal 100
        if (abs($totalWeight - 100) > 0.01) {
            return false;
        }

        return true;
    }

    public function computeResults(ElectionPosition $position, Collection $votes): array
    {
        $tally = [];

        foreach ($votes as $vote) {
            foreach ($vote->vote_data['weights'] ?? [] as $entry) {
                $candidateId = $entry['candidate_id'];
                $tally[$candidateId] = ($tally[$candidateId] ?? 0) + $entry['weight'];
            }
        }

        $totalWeight = array_sum($tally);
        arsort($tally);

        $results = [];
        $rank = 0;
        $seatsAvailable = $position->available_seats;

        foreach ($tally as $candidateId => $weight) {
            $rank++;
            $results[] = [
                'candidate_id' => $candidateId,
                'votes_received' => round($weight, 2),
                'vote_percentage' => $totalWeight > 0 ? round(($weight / $totalWeight) * 100, 4) : 0,
                'rank' => $rank,
                'is_winner' => $rank <= $seatsAvailable,
                'is_tie' => false,
            ];
        }

        return $results;
    }

    public function getVoteSchema(): array
    {
        return [
            'type' => 'object',
            'properties' => [
                'weights' => [
                    'type' => 'array',
                    'items' => [
                        'type' => 'object',
                        'properties' => [
                            'candidate_id' => ['type' => 'integer'],
                            'weight' => ['type' => 'number', 'minimum' => 0, 'maximum' => 100],
                        ],
                    ],
                    'description' => 'Distribute 100 points across candidates',
                ],
            ],
            'required' => ['weights'],
        ];
    }

    public function getDisplayName(): string
    {
        return 'Weighted Voting';
    }
}
