from __future__ import unicode_literals

from collections import defaultdict
from os import chmod, rename
from os.path import dirname
from tempfile import NamedTemporaryFile

from django.core.management.base import BaseCommand, CommandError
from django.db import reset_queries

from candidates.csv_helpers import list_to_csv
from candidates.models import PersonExtra
from candidates.models.fields import get_complex_popolo_fields
from elections.models import Election


FETCH_AT_A_TIME = 1000


def queryset_iterator(qs, complex_popolo_fields):
    # To save building up a huge list of queries when DEBUG = True,
    # call reset_queries:
    reset_queries()
    start_index = 0
    while True:
        chunk_qs = qs.order_by('pk')[start_index:start_index + FETCH_AT_A_TIME]
        empty = True
        for person_extra in chunk_qs.joins_for_csv_output():
            empty = False
            person_extra.complex_popolo_fields = complex_popolo_fields
            yield person_extra
        if empty:
            return
        start_index += FETCH_AT_A_TIME


def safely_write(output_filename, people, group_by_post):
    csv = list_to_csv(people, group_by_post)
    # Write to a temporary file and atomically rename into place:
    ntf = NamedTemporaryFile(
        delete=False,
        dir=dirname(output_filename)
    )
    ntf.write(csv.encode('utf-8'))
    chmod(ntf.name, 0o644)
    rename(ntf.name, output_filename)


class Command(BaseCommand):

    help = "Output CSV files for all elections"

    def add_arguments(self, parser):
        parser.add_argument(
            'OUTPUT-PREFIX',
            help='The prefix for output filenames'
        )
        parser.add_argument(
            '--site-base-url',
            help='The base URL of the site (for full image URLs)'
        )
        parser.add_argument(
            '--election',
            metavar='ELECTION-SLUG',
            help='Only output CSV for the election with this slug'
        )

    def get_people(self, election, qs):
        all_people = []
        elected_people = []
        for person_extra in queryset_iterator(
                qs, self.complex_popolo_fields
        ):
            for d in person_extra.as_list_of_dicts(
                election,
                base_url=self.options['site_base_url']
            ):
                all_people.append(d)
                if d['elected'] == 'True':
                    elected_people.append(d)
        return all_people, elected_people

    def handle(self, **options):
        if options['election']:
            try:
                all_elections = [Election.objects.get(slug=options['election'])]
            except Election.DoesNotExist:
                message = "Couldn't find an election with slug {election_slug}"
                raise CommandError(message.format(election_slug=options['election']))
        else:
            all_elections = list(Election.objects.all()) + [None]

        self.options = options
        self.complex_popolo_fields = get_complex_popolo_fields()

        for election in all_elections:
            if election is None:
                # Get information for every candidate in every
                # election.
                qs = PersonExtra.objects.all()
                all_people, elected_people = self.get_people(election, qs)
                output_filenames = {
                    'all': options['OUTPUT-PREFIX'] + '-all.csv',
                    'elected': options['OUTPUT-PREFIX'] + '-elected-all.csv'
                }
            else:
                # Only get the candidates standing in that particular
                # election
                role = election.candidate_membership_role
                qs = PersonExtra.objects.filter(
                    base__memberships__extra__election=election,
                    base__memberships__role=role,
                )
                all_people, elected_people = self.get_people(election, qs)
                output_filenames = {
                    'all': options['OUTPUT-PREFIX'] + \
                        '-' + election.slug + '.csv',
                    'elected': options['OUTPUT-PREFIX'] +
                        '-elected-' + election.slug + '.csv',
                }
            group_by_post = election is not None
            safely_write(
                output_filenames['all'],
                all_people,
                group_by_post,
            )
            safely_write(
                output_filenames['elected'],
                elected_people,
                group_by_post,
            )