from django.shortcuts import render
from rest_framework import viewsets, permissions, generics, decorators
from .models import Voter, Candidate, Position, Vote, Election
from .serializers import (VoterSerializer, LoginSerializer, AdminSerializer,
                          FileUploadSerializer, CandidateSerializer,
                          PositionSerializer, ElectionSerializer,
                          VoteSerializer)
from rest_framework.response import Response
from django.contrib.auth import login, logout
from django.contrib.auth.models import User
from fileUpload.models import FileUpload
import csv
from io import StringIO
from datetime import datetime
from rest_framework_simplejwt.tokens import RefreshToken
from .data import dob_voter_id
from .check import check
from django.utils import timezone
from django.db.models import Q
from boltons.dictutils import OrderedMultiDict


# Create your views here.
# VOTER API
class VoterView(viewsets.ModelViewSet):
    queryset = Voter.objects.all()
    serializer_class = VoterSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

class ElectionView(viewsets.ModelViewSet):
  serializer_class = ElectionSerializer
  queryset = Election.objects.filter(end_date__gte=timezone.now())
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

# GET THE CURRENT USER
class AdminUser(generics.ListAPIView):
  serializer_class = AdminSerializer
  permission_classes = (permissions.IsAuthenticated,)
  lookup_url_kwarg = "uid"

  def get_queryset(self):
    uid = self.kwargs.get(self.lookup_url_kwarg)
    user = User.objects.filter(id = uid)
    return user


# GET BY VOTER_ID
class VoterIdView(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request, **kwargs):
    id_num = kwargs.get('voter_id')
    query = Q(voter__id_number = id_num)
    query.add(
      Q(candidate__position__election__end_date__gte=timezone.now()), Q.AND)
    res = Vote.objects.filter(query)
    if not res:
      ress = Voter.objects.get(id_number = id_num)
      return Response({
        "voterId": ress.id
      })
    return Response({
      "status": "You have already voted."
    })


# GET BY VOTER_ID WITH ELECTION ID
class VoterIdNumView(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request, **kwargs):
    id_num = kwargs.get('voter_id')
    elec_id = kwargs.get("elec_id")
    query = Q(voter__id_number = id_num)
    query.add(
      Q(candidate__position__election=elec_id), Q.AND)
    res = Vote.objects.filter(query)
    if not res:
      ress = Voter.objects.get(id_number = id_num)
      return Response({
        "voterId": ress.id
      })
    return Response({
      "status": "You have already voted."
    })


# GET ALL CANDIDATES
class CandidateView(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request):
    query = Candidate.objects.filter(
    position__election__end_date__gte=timezone.now()).order_by('date_added')
    
    position = {(a.position.id, a.position.position_description) for a in query}

    response = [{
      "id": a.id,
      "candidate": f'{a.candidate.first_name} {a.candidate.last_name}',
      "candidate_id": a.id,
      "position": a.position.id} for a in query]

    return Response({
      "election": [
        a.position.election.election_description for a in query][1],
      "position": position,
      "data": response
    })
  

class VoteView(viewsets.ModelViewSet):
  queryset = Vote.objects.all()
  serializer_class = VoteSerializer


# GET VOTES BY ELECTION ID
class VotesData(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request, **kwargs):
    elec_id = kwargs.get("euid")
    query = Candidate.objects.filter(position__election = elec_id)

    position = {(a.position.id, a.position.position_description) for a in query}

    votes = Vote.objects.filter(candidate__id__in = [a.id for a in query])

    totalvoter = len({a.voter.id for a in votes})

    v = [(a.candidate.id, a.rank) for a in votes]

    # GROUP DATA BY CANDIDATE ID
    grouped = OrderedMultiDict(v).todict(multi=True)

    for vote in grouped:
      data = {"one": grouped[vote].count(x) for x in grouped[vote] if x == 1}
      if "one" in data:
        percent = round(((data["one"] / totalvoter) * 100))
        grouped[vote] = {"vote": data["one"], "percent": percent}
      else:
        grouped[vote] = {"vote": 0, "percent": 0}
      
    response = [{
      "id": a.id,
      "candidate": f'{a.candidate.first_name} {a.candidate.last_name}',
      "candidate_id": a.id,
      "position": a.position.id,
      "percent": 0} for a in query]

    for res in response:
      for vote in grouped:
        if res["candidate_id"] == vote:
          res["votes"] = grouped[vote]["vote"]
          res["percent"] = grouped[vote]["percent"]
          
    
    # GET THE LEADING CANDIDATE(S)
    _res = [{
            "id": a["id"], "candidate": a["candidate"],
            "position": a["position"], "percent": a["percent"]
            } for a in response]

    leads = []
    for pos in position:
      data = [dt for dt in _res if pos[0] == dt["position"]]
      func = check(data)
      if func != "NO WINNER":
        leads.append(func)
      elif func is None:
        pass

    if query:
      return Response({
        "election": [{"id":a.position.election.id,
          "data": a.position.election.election_description} 
          for a in query][1],
        "position": position,
        "candidates": response,
        "tot_voter" : totalvoter,
        "leading": leads
      })
    else:
      return Response({
        "status": "NOT FOUND."
      })
    

# GET VOTES STATISTICS
class GetVotes(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request):
    query = Candidate.objects.filter(
      position__election__end_date__gte=timezone.now()).order_by('date_added')
    
    position = {(a.position.id, a.position.position_description) for a in query}

    votes = Vote.objects.filter(candidate__id__in = [a.id for a in query])

    totalvoter = len({a.voter.id for a in votes})

    v = [(a.candidate.id, a.rank) for a in votes]

    # GROUP DATA BY CANDIDATE ID
    grouped = OrderedMultiDict(v).todict(multi=True)

    for vote in grouped:
      data = {"one": grouped[vote].count(x) for x in grouped[vote] if x == 1}
      if "one" in data:
        percent = round(((data["one"] / totalvoter) * 100))
        grouped[vote] = {"vote": data["one"], "percent": percent}
      else:
        grouped[vote] = {"vote": 0, "percent": 0}
      
    response = [{
      "id": a.id,
      "candidate": f'{a.candidate.first_name} {a.candidate.last_name}',
      "candidate_id": a.id,
      "position": a.position.id,
      "percent": 0} for a in query]

    for res in response:
      for vote in grouped:
        if res["candidate_id"] == vote:
          res["votes"] = grouped[vote]["vote"]
          res["percent"] = grouped[vote]["percent"]
          
    
    # GET THE LEADING CANDIDATE(S)
    _res = [{
            "id": a["id"], "candidate": a["candidate"],
            "position": a["position"], "percent": a["percent"]
            } for a in response]

    leads = []
    for pos in position:
      data = [dt for dt in _res if pos[0] == dt["position"]]
      func = check(data)
      if func != "NO WINNER":
        leads.append(func)
      elif func is None:
        pass

    
    return Response({
      "election": [
        a.position.election.election_description for a in query][1],
      "position": position,
      "candidates": response,
      "tot_voter" : totalvoter,
      "leading": leads
    })


# LOGIN & LOGOUT
@decorators.api_view(["POST"])
def login_view(request):
  serializer = LoginSerializer(data=request.data)
  serializer.is_valid(raise_exception=True)
  user = serializer.validated_data
  login(request, user)
  token = RefreshToken.for_user(user)
  return Response({
    "access": str(token.access_token)
  })


@decorators.api_view(["GET"])
def logout_view(request):
  logout(request)
  return Response({"status": "Successfully logged out."})


# REGISTER VOTER
class FileUploadView(generics.GenericAPIView):
  serializer_class = FileUploadSerializer
  permission_classes = (permissions.IsAuthenticated,)

  def post(self, request):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    _file = serializer.validated_data['file']
    data = _file.file.read().decode('utf-8')
    csv_data = csv.DictReader(StringIO(data))
    for voter in csv_data:
      dob = dob_voter_id(voter['birthday'])
      voter_id = dob[1]

      save_data = Voter.objects.create(
        first_name = voter['first_name'],
        last_name = voter['last_name'],
        birthday = dob[0],
        civil_status = voter['civil_status'],
        citizenship = voter['citizenship'],
        address = voter['address'],
        precinct_number = voter['precinct_number'],
        id_number = voter_id,
        created_at = datetime.now(),
      )
      save_data.save()

    return Response({"status": "Successfully uploaded."})


class VoterRegistrationView(generics.GenericAPIView):
  serializer_class = VoterSerializer
  permission_classes = (permissions.IsAuthenticated,)

  def post(self, request):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    dob = dob_voter_id(serializer.validated_data['birthday'])
    voter_id = dob[1]

    data = Voter.objects.create(
      first_name = serializer.validated_data['first_name'],
      last_name = serializer.validated_data['last_name'],
      birthday = dob[0],
      civil_status = serializer.validated_data['civil_status'],
      citizenship = serializer.validated_data['citizenship'],
      address = serializer.validated_data['address'],
      precinct_number = serializer.validated_data['precinct_number'],
      id_number = voter_id,
      created_at = datetime.now(),
    )
    data.save()

    return Response({'status': "Voter successfully registered."})

661cd6b9de324b9a1b9586d5da6e81684ec2040c
<mask token>


class VoterIdView(generics.GenericAPIView):
    <mask token>

    def get(self, request, **kwargs):
        id_num = kwargs.get('voter_id')
        query = Q(voter__id_number=id_num)
        query.add(Q(candidate__position__election__end_date__gte=timezone.
            now()), Q.AND)
        res = Vote.objects.filter(query)
        if not res:
            ress = Voter.objects.get(id_number=id_num)
            return Response({'voterId': ress.id})
        return Response({'status': 'You have already voted.'})


class VoterIdNumView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        id_num = kwargs.get('voter_id')
        elec_id = kwargs.get('elec_id')
        query = Q(voter__id_number=id_num)
        query.add(Q(candidate__position__election=elec_id), Q.AND)
        res = Vote.objects.filter(query)
        if not res:
            ress = Voter.objects.get(id_number=id_num)
            return Response({'voterId': ress.id})
        return Response({'status': 'You have already voted.'})


class CandidateView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request):
        query = Candidate.objects.filter(position__election__end_date__gte=
            timezone.now()).order_by('date_added')
        position = {(a.position.id, a.position.position_description) for a in
            query}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id} for a in query]
        return Response({'election': [a.position.election.
            election_description for a in query][1], 'position': position,
            'data': response})


class VoteView(viewsets.ModelViewSet):
    queryset = Vote.objects.all()
    serializer_class = VoteSerializer


class VotesData(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        elec_id = kwargs.get('euid')
        query = Candidate.objects.filter(position__election=elec_id)
        position = {(a.position.id, a.position.position_description) for a in
            query}
        votes = Vote.objects.filter(candidate__id__in=[a.id for a in query])
        totalvoter = len({a.voter.id for a in votes})
        v = [(a.candidate.id, a.rank) for a in votes]
        grouped = OrderedMultiDict(v).todict(multi=True)
        for vote in grouped:
            data = {'one': grouped[vote].count(x) for x in grouped[vote] if
                x == 1}
            if 'one' in data:
                percent = round(data['one'] / totalvoter * 100)
                grouped[vote] = {'vote': data['one'], 'percent': percent}
            else:
                grouped[vote] = {'vote': 0, 'percent': 0}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id, 'percent': 0} for
            a in query]
        for res in response:
            for vote in grouped:
                if res['candidate_id'] == vote:
                    res['votes'] = grouped[vote]['vote']
                    res['percent'] = grouped[vote]['percent']
        _res = [{'id': a['id'], 'candidate': a['candidate'], 'position': a[
            'position'], 'percent': a['percent']} for a in response]
        leads = []
        for pos in position:
            data = [dt for dt in _res if pos[0] == dt['position']]
            func = check(data)
            if func != 'NO WINNER':
                leads.append(func)
            elif func is None:
                pass
        if query:
            return Response({'election': [{'id': a.position.election.id,
                'data': a.position.election.election_description} for a in
                query][1], 'position': position, 'candidates': response,
                'tot_voter': totalvoter, 'leading': leads})
        else:
            return Response({'status': 'NOT FOUND.'})


class GetVotes(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request):
        query = Candidate.objects.filter(position__election__end_date__gte=
            timezone.now()).order_by('date_added')
        position = {(a.position.id, a.position.position_description) for a in
            query}
        votes = Vote.objects.filter(candidate__id__in=[a.id for a in query])
        totalvoter = len({a.voter.id for a in votes})
        v = [(a.candidate.id, a.rank) for a in votes]
        grouped = OrderedMultiDict(v).todict(multi=True)
        for vote in grouped:
            data = {'one': grouped[vote].count(x) for x in grouped[vote] if
                x == 1}
            if 'one' in data:
                percent = round(data['one'] / totalvoter * 100)
                grouped[vote] = {'vote': data['one'], 'percent': percent}
            else:
                grouped[vote] = {'vote': 0, 'percent': 0}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id, 'percent': 0} for
            a in query]
        for res in response:
            for vote in grouped:
                if res['candidate_id'] == vote:
                    res['votes'] = grouped[vote]['vote']
                    res['percent'] = grouped[vote]['percent']
        _res = [{'id': a['id'], 'candidate': a['candidate'], 'position': a[
            'position'], 'percent': a['percent']} for a in response]
        leads = []
        for pos in position:
            data = [dt for dt in _res if pos[0] == dt['position']]
            func = check(data)
            if func != 'NO WINNER':
                leads.append(func)
            elif func is None:
                pass
        return Response({'election': [a.position.election.
            election_description for a in query][1], 'position': position,
            'candidates': response, 'tot_voter': totalvoter, 'leading': leads})


<mask token>


class FileUploadView(generics.GenericAPIView):
    serializer_class = FileUploadSerializer
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        _file = serializer.validated_data['file']
        data = _file.file.read().decode('utf-8')
        csv_data = csv.DictReader(StringIO(data))
        for voter in csv_data:
            dob = dob_voter_id(voter['birthday'])
            voter_id = dob[1]
            save_data = Voter.objects.create(first_name=voter['first_name'],
                last_name=voter['last_name'], birthday=dob[0], civil_status
                =voter['civil_status'], citizenship=voter['citizenship'],
                address=voter['address'], precinct_number=voter[
                'precinct_number'], id_number=voter_id, created_at=datetime
                .now())
            save_data.save()
        return Response({'status': 'Successfully uploaded.'})


class VoterRegistrationView(generics.GenericAPIView):
    serializer_class = VoterSerializer
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        dob = dob_voter_id(serializer.validated_data['birthday'])
        voter_id = dob[1]
        data = Voter.objects.create(first_name=serializer.validated_data[
            'first_name'], last_name=serializer.validated_data['last_name'],
            birthday=dob[0], civil_status=serializer.validated_data[
            'civil_status'], citizenship=serializer.validated_data[
            'citizenship'], address=serializer.validated_data['address'],
            precinct_number=serializer.validated_data['precinct_number'],
            id_number=voter_id, created_at=datetime.now())
        data.save()
        return Response({'status': 'Voter successfully registered.'})

<mask token>


class AdminUser(generics.ListAPIView):
    <mask token>
    <mask token>
    <mask token>
    <mask token>


class VoterIdView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        id_num = kwargs.get('voter_id')
        query = Q(voter__id_number=id_num)
        query.add(Q(candidate__position__election__end_date__gte=timezone.
            now()), Q.AND)
        res = Vote.objects.filter(query)
        if not res:
            ress = Voter.objects.get(id_number=id_num)
            return Response({'voterId': ress.id})
        return Response({'status': 'You have already voted.'})


class VoterIdNumView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        id_num = kwargs.get('voter_id')
        elec_id = kwargs.get('elec_id')
        query = Q(voter__id_number=id_num)
        query.add(Q(candidate__position__election=elec_id), Q.AND)
        res = Vote.objects.filter(query)
        if not res:
            ress = Voter.objects.get(id_number=id_num)
            return Response({'voterId': ress.id})
        return Response({'status': 'You have already voted.'})


class CandidateView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request):
        query = Candidate.objects.filter(position__election__end_date__gte=
            timezone.now()).order_by('date_added')
        position = {(a.position.id, a.position.position_description) for a in
            query}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id} for a in query]
        return Response({'election': [a.position.election.
            election_description for a in query][1], 'position': position,
            'data': response})


class VoteView(viewsets.ModelViewSet):
    queryset = Vote.objects.all()
    serializer_class = VoteSerializer


class VotesData(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        elec_id = kwargs.get('euid')
        query = Candidate.objects.filter(position__election=elec_id)
        position = {(a.position.id, a.position.position_description) for a in
            query}
        votes = Vote.objects.filter(candidate__id__in=[a.id for a in query])
        totalvoter = len({a.voter.id for a in votes})
        v = [(a.candidate.id, a.rank) for a in votes]
        grouped = OrderedMultiDict(v).todict(multi=True)
        for vote in grouped:
            data = {'one': grouped[vote].count(x) for x in grouped[vote] if
                x == 1}
            if 'one' in data:
                percent = round(data['one'] / totalvoter * 100)
                grouped[vote] = {'vote': data['one'], 'percent': percent}
            else:
                grouped[vote] = {'vote': 0, 'percent': 0}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id, 'percent': 0} for
            a in query]
        for res in response:
            for vote in grouped:
                if res['candidate_id'] == vote:
                    res['votes'] = grouped[vote]['vote']
                    res['percent'] = grouped[vote]['percent']
        _res = [{'id': a['id'], 'candidate': a['candidate'], 'position': a[
            'position'], 'percent': a['percent']} for a in response]
        leads = []
        for pos in position:
            data = [dt for dt in _res if pos[0] == dt['position']]
            func = check(data)
            if func != 'NO WINNER':
                leads.append(func)
            elif func is None:
                pass
        if query:
            return Response({'election': [{'id': a.position.election.id,
                'data': a.position.election.election_description} for a in
                query][1], 'position': position, 'candidates': response,
                'tot_voter': totalvoter, 'leading': leads})
        else:
            return Response({'status': 'NOT FOUND.'})


class GetVotes(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request):
        query = Candidate.objects.filter(position__election__end_date__gte=
            timezone.now()).order_by('date_added')
        position = {(a.position.id, a.position.position_description) for a in
            query}
        votes = Vote.objects.filter(candidate__id__in=[a.id for a in query])
        totalvoter = len({a.voter.id for a in votes})
        v = [(a.candidate.id, a.rank) for a in votes]
        grouped = OrderedMultiDict(v).todict(multi=True)
        for vote in grouped:
            data = {'one': grouped[vote].count(x) for x in grouped[vote] if
                x == 1}
            if 'one' in data:
                percent = round(data['one'] / totalvoter * 100)
                grouped[vote] = {'vote': data['one'], 'percent': percent}
            else:
                grouped[vote] = {'vote': 0, 'percent': 0}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id, 'percent': 0} for
            a in query]
        for res in response:
            for vote in grouped:
                if res['candidate_id'] == vote:
                    res['votes'] = grouped[vote]['vote']
                    res['percent'] = grouped[vote]['percent']
        _res = [{'id': a['id'], 'candidate': a['candidate'], 'position': a[
            'position'], 'percent': a['percent']} for a in response]
        leads = []
        for pos in position:
            data = [dt for dt in _res if pos[0] == dt['position']]
            func = check(data)
            if func != 'NO WINNER':
                leads.append(func)
            elif func is None:
                pass
        return Response({'election': [a.position.election.
            election_description for a in query][1], 'position': position,
            'candidates': response, 'tot_voter': totalvoter, 'leading': leads})


<mask token>


class FileUploadView(generics.GenericAPIView):
    serializer_class = FileUploadSerializer
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        _file = serializer.validated_data['file']
        data = _file.file.read().decode('utf-8')
        csv_data = csv.DictReader(StringIO(data))
        for voter in csv_data:
            dob = dob_voter_id(voter['birthday'])
            voter_id = dob[1]
            save_data = Voter.objects.create(first_name=voter['first_name'],
                last_name=voter['last_name'], birthday=dob[0], civil_status
                =voter['civil_status'], citizenship=voter['citizenship'],
                address=voter['address'], precinct_number=voter[
                'precinct_number'], id_number=voter_id, created_at=datetime
                .now())
            save_data.save()
        return Response({'status': 'Successfully uploaded.'})


class VoterRegistrationView(generics.GenericAPIView):
    serializer_class = VoterSerializer
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        dob = dob_voter_id(serializer.validated_data['birthday'])
        voter_id = dob[1]
        data = Voter.objects.create(first_name=serializer.validated_data[
            'first_name'], last_name=serializer.validated_data['last_name'],
            birthday=dob[0], civil_status=serializer.validated_data[
            'civil_status'], citizenship=serializer.validated_data[
            'citizenship'], address=serializer.validated_data['address'],
            precinct_number=serializer.validated_data['precinct_number'],
            id_number=voter_id, created_at=datetime.now())
        data.save()
        return Response({'status': 'Voter successfully registered.'})

<mask token>


class AdminUser(generics.ListAPIView):
    serializer_class = AdminSerializer
    permission_classes = permissions.IsAuthenticated,
    lookup_url_kwarg = 'uid'

    def get_queryset(self):
        uid = self.kwargs.get(self.lookup_url_kwarg)
        user = User.objects.filter(id=uid)
        return user


class VoterIdView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        id_num = kwargs.get('voter_id')
        query = Q(voter__id_number=id_num)
        query.add(Q(candidate__position__election__end_date__gte=timezone.
            now()), Q.AND)
        res = Vote.objects.filter(query)
        if not res:
            ress = Voter.objects.get(id_number=id_num)
            return Response({'voterId': ress.id})
        return Response({'status': 'You have already voted.'})


class VoterIdNumView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        id_num = kwargs.get('voter_id')
        elec_id = kwargs.get('elec_id')
        query = Q(voter__id_number=id_num)
        query.add(Q(candidate__position__election=elec_id), Q.AND)
        res = Vote.objects.filter(query)
        if not res:
            ress = Voter.objects.get(id_number=id_num)
            return Response({'voterId': ress.id})
        return Response({'status': 'You have already voted.'})


class CandidateView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request):
        query = Candidate.objects.filter(position__election__end_date__gte=
            timezone.now()).order_by('date_added')
        position = {(a.position.id, a.position.position_description) for a in
            query}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id} for a in query]
        return Response({'election': [a.position.election.
            election_description for a in query][1], 'position': position,
            'data': response})


class VoteView(viewsets.ModelViewSet):
    queryset = Vote.objects.all()
    serializer_class = VoteSerializer


class VotesData(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        elec_id = kwargs.get('euid')
        query = Candidate.objects.filter(position__election=elec_id)
        position = {(a.position.id, a.position.position_description) for a in
            query}
        votes = Vote.objects.filter(candidate__id__in=[a.id for a in query])
        totalvoter = len({a.voter.id for a in votes})
        v = [(a.candidate.id, a.rank) for a in votes]
        grouped = OrderedMultiDict(v).todict(multi=True)
        for vote in grouped:
            data = {'one': grouped[vote].count(x) for x in grouped[vote] if
                x == 1}
            if 'one' in data:
                percent = round(data['one'] / totalvoter * 100)
                grouped[vote] = {'vote': data['one'], 'percent': percent}
            else:
                grouped[vote] = {'vote': 0, 'percent': 0}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id, 'percent': 0} for
            a in query]
        for res in response:
            for vote in grouped:
                if res['candidate_id'] == vote:
                    res['votes'] = grouped[vote]['vote']
                    res['percent'] = grouped[vote]['percent']
        _res = [{'id': a['id'], 'candidate': a['candidate'], 'position': a[
            'position'], 'percent': a['percent']} for a in response]
        leads = []
        for pos in position:
            data = [dt for dt in _res if pos[0] == dt['position']]
            func = check(data)
            if func != 'NO WINNER':
                leads.append(func)
            elif func is None:
                pass
        if query:
            return Response({'election': [{'id': a.position.election.id,
                'data': a.position.election.election_description} for a in
                query][1], 'position': position, 'candidates': response,
                'tot_voter': totalvoter, 'leading': leads})
        else:
            return Response({'status': 'NOT FOUND.'})


class GetVotes(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request):
        query = Candidate.objects.filter(position__election__end_date__gte=
            timezone.now()).order_by('date_added')
        position = {(a.position.id, a.position.position_description) for a in
            query}
        votes = Vote.objects.filter(candidate__id__in=[a.id for a in query])
        totalvoter = len({a.voter.id for a in votes})
        v = [(a.candidate.id, a.rank) for a in votes]
        grouped = OrderedMultiDict(v).todict(multi=True)
        for vote in grouped:
            data = {'one': grouped[vote].count(x) for x in grouped[vote] if
                x == 1}
            if 'one' in data:
                percent = round(data['one'] / totalvoter * 100)
                grouped[vote] = {'vote': data['one'], 'percent': percent}
            else:
                grouped[vote] = {'vote': 0, 'percent': 0}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id, 'percent': 0} for
            a in query]
        for res in response:
            for vote in grouped:
                if res['candidate_id'] == vote:
                    res['votes'] = grouped[vote]['vote']
                    res['percent'] = grouped[vote]['percent']
        _res = [{'id': a['id'], 'candidate': a['candidate'], 'position': a[
            'position'], 'percent': a['percent']} for a in response]
        leads = []
        for pos in position:
            data = [dt for dt in _res if pos[0] == dt['position']]
            func = check(data)
            if func != 'NO WINNER':
                leads.append(func)
            elif func is None:
                pass
        return Response({'election': [a.position.election.
            election_description for a in query][1], 'position': position,
            'candidates': response, 'tot_voter': totalvoter, 'leading': leads})


<mask token>


class FileUploadView(generics.GenericAPIView):
    serializer_class = FileUploadSerializer
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        _file = serializer.validated_data['file']
        data = _file.file.read().decode('utf-8')
        csv_data = csv.DictReader(StringIO(data))
        for voter in csv_data:
            dob = dob_voter_id(voter['birthday'])
            voter_id = dob[1]
            save_data = Voter.objects.create(first_name=voter['first_name'],
                last_name=voter['last_name'], birthday=dob[0], civil_status
                =voter['civil_status'], citizenship=voter['citizenship'],
                address=voter['address'], precinct_number=voter[
                'precinct_number'], id_number=voter_id, created_at=datetime
                .now())
            save_data.save()
        return Response({'status': 'Successfully uploaded.'})


class VoterRegistrationView(generics.GenericAPIView):
    serializer_class = VoterSerializer
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        dob = dob_voter_id(serializer.validated_data['birthday'])
        voter_id = dob[1]
        data = Voter.objects.create(first_name=serializer.validated_data[
            'first_name'], last_name=serializer.validated_data['last_name'],
            birthday=dob[0], civil_status=serializer.validated_data[
            'civil_status'], citizenship=serializer.validated_data[
            'citizenship'], address=serializer.validated_data['address'],
            precinct_number=serializer.validated_data['precinct_number'],
            id_number=voter_id, created_at=datetime.now())
        data.save()
        return Response({'status': 'Voter successfully registered.'})

<mask token>


class ElectionView(viewsets.ModelViewSet):
    <mask token>
    <mask token>
    <mask token>


class AdminUser(generics.ListAPIView):
    serializer_class = AdminSerializer
    permission_classes = permissions.IsAuthenticated,
    lookup_url_kwarg = 'uid'

    def get_queryset(self):
        uid = self.kwargs.get(self.lookup_url_kwarg)
        user = User.objects.filter(id=uid)
        return user


class VoterIdView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        id_num = kwargs.get('voter_id')
        query = Q(voter__id_number=id_num)
        query.add(Q(candidate__position__election__end_date__gte=timezone.
            now()), Q.AND)
        res = Vote.objects.filter(query)
        if not res:
            ress = Voter.objects.get(id_number=id_num)
            return Response({'voterId': ress.id})
        return Response({'status': 'You have already voted.'})


class VoterIdNumView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        id_num = kwargs.get('voter_id')
        elec_id = kwargs.get('elec_id')
        query = Q(voter__id_number=id_num)
        query.add(Q(candidate__position__election=elec_id), Q.AND)
        res = Vote.objects.filter(query)
        if not res:
            ress = Voter.objects.get(id_number=id_num)
            return Response({'voterId': ress.id})
        return Response({'status': 'You have already voted.'})


class CandidateView(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request):
        query = Candidate.objects.filter(position__election__end_date__gte=
            timezone.now()).order_by('date_added')
        position = {(a.position.id, a.position.position_description) for a in
            query}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id} for a in query]
        return Response({'election': [a.position.election.
            election_description for a in query][1], 'position': position,
            'data': response})


class VoteView(viewsets.ModelViewSet):
    queryset = Vote.objects.all()
    serializer_class = VoteSerializer


class VotesData(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request, **kwargs):
        elec_id = kwargs.get('euid')
        query = Candidate.objects.filter(position__election=elec_id)
        position = {(a.position.id, a.position.position_description) for a in
            query}
        votes = Vote.objects.filter(candidate__id__in=[a.id for a in query])
        totalvoter = len({a.voter.id for a in votes})
        v = [(a.candidate.id, a.rank) for a in votes]
        grouped = OrderedMultiDict(v).todict(multi=True)
        for vote in grouped:
            data = {'one': grouped[vote].count(x) for x in grouped[vote] if
                x == 1}
            if 'one' in data:
                percent = round(data['one'] / totalvoter * 100)
                grouped[vote] = {'vote': data['one'], 'percent': percent}
            else:
                grouped[vote] = {'vote': 0, 'percent': 0}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id, 'percent': 0} for
            a in query]
        for res in response:
            for vote in grouped:
                if res['candidate_id'] == vote:
                    res['votes'] = grouped[vote]['vote']
                    res['percent'] = grouped[vote]['percent']
        _res = [{'id': a['id'], 'candidate': a['candidate'], 'position': a[
            'position'], 'percent': a['percent']} for a in response]
        leads = []
        for pos in position:
            data = [dt for dt in _res if pos[0] == dt['position']]
            func = check(data)
            if func != 'NO WINNER':
                leads.append(func)
            elif func is None:
                pass
        if query:
            return Response({'election': [{'id': a.position.election.id,
                'data': a.position.election.election_description} for a in
                query][1], 'position': position, 'candidates': response,
                'tot_voter': totalvoter, 'leading': leads})
        else:
            return Response({'status': 'NOT FOUND.'})


class GetVotes(generics.GenericAPIView):
    permission_classes = permissions.IsAuthenticatedOrReadOnly,

    def get(self, request):
        query = Candidate.objects.filter(position__election__end_date__gte=
            timezone.now()).order_by('date_added')
        position = {(a.position.id, a.position.position_description) for a in
            query}
        votes = Vote.objects.filter(candidate__id__in=[a.id for a in query])
        totalvoter = len({a.voter.id for a in votes})
        v = [(a.candidate.id, a.rank) for a in votes]
        grouped = OrderedMultiDict(v).todict(multi=True)
        for vote in grouped:
            data = {'one': grouped[vote].count(x) for x in grouped[vote] if
                x == 1}
            if 'one' in data:
                percent = round(data['one'] / totalvoter * 100)
                grouped[vote] = {'vote': data['one'], 'percent': percent}
            else:
                grouped[vote] = {'vote': 0, 'percent': 0}
        response = [{'id': a.id, 'candidate':
            f'{a.candidate.first_name} {a.candidate.last_name}',
            'candidate_id': a.id, 'position': a.position.id, 'percent': 0} for
            a in query]
        for res in response:
            for vote in grouped:
                if res['candidate_id'] == vote:
                    res['votes'] = grouped[vote]['vote']
                    res['percent'] = grouped[vote]['percent']
        _res = [{'id': a['id'], 'candidate': a['candidate'], 'position': a[
            'position'], 'percent': a['percent']} for a in response]
        leads = []
        for pos in position:
            data = [dt for dt in _res if pos[0] == dt['position']]
            func = check(data)
            if func != 'NO WINNER':
                leads.append(func)
            elif func is None:
                pass
        return Response({'election': [a.position.election.
            election_description for a in query][1], 'position': position,
            'candidates': response, 'tot_voter': totalvoter, 'leading': leads})


<mask token>


class FileUploadView(generics.GenericAPIView):
    serializer_class = FileUploadSerializer
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        _file = serializer.validated_data['file']
        data = _file.file.read().decode('utf-8')
        csv_data = csv.DictReader(StringIO(data))
        for voter in csv_data:
            dob = dob_voter_id(voter['birthday'])
            voter_id = dob[1]
            save_data = Voter.objects.create(first_name=voter['first_name'],
                last_name=voter['last_name'], birthday=dob[0], civil_status
                =voter['civil_status'], citizenship=voter['citizenship'],
                address=voter['address'], precinct_number=voter[
                'precinct_number'], id_number=voter_id, created_at=datetime
                .now())
            save_data.save()
        return Response({'status': 'Successfully uploaded.'})


class VoterRegistrationView(generics.GenericAPIView):
    serializer_class = VoterSerializer
    permission_classes = permissions.IsAuthenticated,

    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        dob = dob_voter_id(serializer.validated_data['birthday'])
        voter_id = dob[1]
        data = Voter.objects.create(first_name=serializer.validated_data[
            'first_name'], last_name=serializer.validated_data['last_name'],
            birthday=dob[0], civil_status=serializer.validated_data[
            'civil_status'], citizenship=serializer.validated_data[
            'citizenship'], address=serializer.validated_data['address'],
            precinct_number=serializer.validated_data['precinct_number'],
            id_number=voter_id, created_at=datetime.now())
        data.save()
        return Response({'status': 'Voter successfully registered.'})

from django.shortcuts import render
from rest_framework import viewsets, permissions, generics, decorators
from .models import Voter, Candidate, Position, Vote, Election
from .serializers import (VoterSerializer, LoginSerializer, AdminSerializer,
                          FileUploadSerializer, CandidateSerializer,
                          PositionSerializer, ElectionSerializer,
                          VoteSerializer)
from rest_framework.response import Response
from django.contrib.auth import login, logout
from django.contrib.auth.models import User
from fileUpload.models import FileUpload
import csv
from io import StringIO
from datetime import datetime
from rest_framework_simplejwt.tokens import RefreshToken
from .data import dob_voter_id
from .check import check
from django.utils import timezone
from django.db.models import Q
from boltons.dictutils import OrderedMultiDict


# Create your views here.
# VOTER API
class VoterView(viewsets.ModelViewSet):
    queryset = Voter.objects.all()
    serializer_class = VoterSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

class ElectionView(viewsets.ModelViewSet):
  serializer_class = ElectionSerializer
  queryset = Election.objects.filter(end_date__gte=timezone.now())
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

# GET THE CURRENT USER
class AdminUser(generics.ListAPIView):
  serializer_class = AdminSerializer
  permission_classes = (permissions.IsAuthenticated,)
  lookup_url_kwarg = "uid"

  def get_queryset(self):
    uid = self.kwargs.get(self.lookup_url_kwarg)
    user = User.objects.filter(id = uid)
    return user


# GET BY VOTER_ID
class VoterIdView(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request, **kwargs):
    id_num = kwargs.get('voter_id')
    query = Q(voter__id_number = id_num)
    query.add(
      Q(candidate__position__election__end_date__gte=timezone.now()), Q.AND)
    res = Vote.objects.filter(query)
    if not res:
      ress = Voter.objects.get(id_number = id_num)
      return Response({
        "voterId": ress.id
      })
    return Response({
      "status": "You have already voted."
    })


# GET BY VOTER_ID WITH ELECTION ID
class VoterIdNumView(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request, **kwargs):
    id_num = kwargs.get('voter_id')
    elec_id = kwargs.get("elec_id")
    query = Q(voter__id_number = id_num)
    query.add(
      Q(candidate__position__election=elec_id), Q.AND)
    res = Vote.objects.filter(query)
    if not res:
      ress = Voter.objects.get(id_number = id_num)
      return Response({
        "voterId": ress.id
      })
    return Response({
      "status": "You have already voted."
    })


# GET ALL CANDIDATES
class CandidateView(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request):
    query = Candidate.objects.filter(
    position__election__end_date__gte=timezone.now()).order_by('date_added')
    
    position = {(a.position.id, a.position.position_description) for a in query}

    response = [{
      "id": a.id,
      "candidate": f'{a.candidate.first_name} {a.candidate.last_name}',
      "candidate_id": a.id,
      "position": a.position.id} for a in query]

    return Response({
      "election": [
        a.position.election.election_description for a in query][1],
      "position": position,
      "data": response
    })
  

class VoteView(viewsets.ModelViewSet):
  queryset = Vote.objects.all()
  serializer_class = VoteSerializer


# GET VOTES BY ELECTION ID
class VotesData(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request, **kwargs):
    elec_id = kwargs.get("euid")
    query = Candidate.objects.filter(position__election = elec_id)

    position = {(a.position.id, a.position.position_description) for a in query}

    votes = Vote.objects.filter(candidate__id__in = [a.id for a in query])

    totalvoter = len({a.voter.id for a in votes})

    v = [(a.candidate.id, a.rank) for a in votes]

    # GROUP DATA BY CANDIDATE ID
    grouped = OrderedMultiDict(v).todict(multi=True)

    for vote in grouped:
      data = {"one": grouped[vote].count(x) for x in grouped[vote] if x == 1}
      if "one" in data:
        percent = round(((data["one"] / totalvoter) * 100))
        grouped[vote] = {"vote": data["one"], "percent": percent}
      else:
        grouped[vote] = {"vote": 0, "percent": 0}
      
    response = [{
      "id": a.id,
      "candidate": f'{a.candidate.first_name} {a.candidate.last_name}',
      "candidate_id": a.id,
      "position": a.position.id,
      "percent": 0} for a in query]

    for res in response:
      for vote in grouped:
        if res["candidate_id"] == vote:
          res["votes"] = grouped[vote]["vote"]
          res["percent"] = grouped[vote]["percent"]
          
    
    # GET THE LEADING CANDIDATE(S)
    _res = [{
            "id": a["id"], "candidate": a["candidate"],
            "position": a["position"], "percent": a["percent"]
            } for a in response]

    leads = []
    for pos in position:
      data = [dt for dt in _res if pos[0] == dt["position"]]
      func = check(data)
      if func != "NO WINNER":
        leads.append(func)
      elif func is None:
        pass

    if query:
      return Response({
        "election": [{"id":a.position.election.id,
          "data": a.position.election.election_description} 
          for a in query][1],
        "position": position,
        "candidates": response,
        "tot_voter" : totalvoter,
        "leading": leads
      })
    else:
      return Response({
        "status": "NOT FOUND."
      })
    

# GET VOTES STATISTICS
class GetVotes(generics.GenericAPIView):
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  def get(self, request):
    query = Candidate.objects.filter(
      position__election__end_date__gte=timezone.now()).order_by('date_added')
    
    position = {(a.position.id, a.position.position_description) for a in query}

    votes = Vote.objects.filter(candidate__id__in = [a.id for a in query])

    totalvoter = len({a.voter.id for a in votes})

    v = [(a.candidate.id, a.rank) for a in votes]

    # GROUP DATA BY CANDIDATE ID
    grouped = OrderedMultiDict(v).todict(multi=True)

    for vote in grouped:
      data = {"one": grouped[vote].count(x) for x in grouped[vote] if x == 1}
      if "one" in data:
        percent = round(((data["one"] / totalvoter) * 100))
        grouped[vote] = {"vote": data["one"], "percent": percent}
      else:
        grouped[vote] = {"vote": 0, "percent": 0}
      
    response = [{
      "id": a.id,
      "candidate": f'{a.candidate.first_name} {a.candidate.last_name}',
      "candidate_id": a.id,
      "position": a.position.id,
      "percent": 0} for a in query]

    for res in response:
      for vote in grouped:
        if res["candidate_id"] == vote:
          res["votes"] = grouped[vote]["vote"]
          res["percent"] = grouped[vote]["percent"]
          
    
    # GET THE LEADING CANDIDATE(S)
    _res = [{
            "id": a["id"], "candidate": a["candidate"],
            "position": a["position"], "percent": a["percent"]
            } for a in response]

    leads = []
    for pos in position:
      data = [dt for dt in _res if pos[0] == dt["position"]]
      func = check(data)
      if func != "NO WINNER":
        leads.append(func)
      elif func is None:
        pass

    
    return Response({
      "election": [
        a.position.election.election_description for a in query][1],
      "position": position,
      "candidates": response,
      "tot_voter" : totalvoter,
      "leading": leads
    })


# LOGIN & LOGOUT
@decorators.api_view(["POST"])
def login_view(request):
  serializer = LoginSerializer(data=request.data)
  serializer.is_valid(raise_exception=True)
  user = serializer.validated_data
  login(request, user)
  token = RefreshToken.for_user(user)
  return Response({
    "access": str(token.access_token)
  })


@decorators.api_view(["GET"])
def logout_view(request):
  logout(request)
  return Response({"status": "Successfully logged out."})


# REGISTER VOTER
class FileUploadView(generics.GenericAPIView):
  serializer_class = FileUploadSerializer
  permission_classes = (permissions.IsAuthenticated,)

  def post(self, request):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    _file = serializer.validated_data['file']
    data = _file.file.read().decode('utf-8')
    csv_data = csv.DictReader(StringIO(data))
    for voter in csv_data:
      dob = dob_voter_id(voter['birthday'])
      voter_id = dob[1]

      save_data = Voter.objects.create(
        first_name = voter['first_name'],
        last_name = voter['last_name'],
        birthday = dob[0],
        civil_status = voter['civil_status'],
        citizenship = voter['citizenship'],
        address = voter['address'],
        precinct_number = voter['precinct_number'],
        id_number = voter_id,
        created_at = datetime.now(),
      )
      save_data.save()

    return Response({"status": "Successfully uploaded."})


class VoterRegistrationView(generics.GenericAPIView):
  serializer_class = VoterSerializer
  permission_classes = (permissions.IsAuthenticated,)

  def post(self, request):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    dob = dob_voter_id(serializer.validated_data['birthday'])
    voter_id = dob[1]

    data = Voter.objects.create(
      first_name = serializer.validated_data['first_name'],
      last_name = serializer.validated_data['last_name'],
      birthday = dob[0],
      civil_status = serializer.validated_data['civil_status'],
      citizenship = serializer.validated_data['citizenship'],
      address = serializer.validated_data['address'],
      precinct_number = serializer.validated_data['precinct_number'],
      id_number = voter_id,
      created_at = datetime.now(),
    )
    data.save()

    return Response({'status': "Voter successfully registered."})
