from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from django.utils.encoding import force_str
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.urls import reverse

from django.views.decorators.csrf import csrf_exempt
from django.contrib.admin.views.decorators import staff_member_required
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile

from tournaments.models.device_token import DeviceToken

from .models import Court, DateInterval, Club, Tournament, CustomUser, Event, Round, GroupStage, Match, TeamScore, TeamRegistration, PlayerRegistration, Purchase, FailedApiCall
from .models import TeamSummon
from datetime import datetime, timedelta
import time

from django.template import loader
from datetime import date
from django.http import JsonResponse, HttpResponse
from django.db.models import Q
import json
import asyncio
import csv
import zipfile

from api.tokens import account_activation_token

from qr_code.qrcode.utils import QRCodeOptions
from .utils.apns import send_push_notification
import os

from .forms import SimpleForm
from django.core.mail import EmailMessage
from datetime import timedelta
from django.utils import timezone

def index(request):

    club_id = request.GET.get('club')
    future = future_tournaments(club_id)
    live = live_tournaments(club_id)
    finished = finished_tournaments(club_id)

    club = None
    if club_id:
        club = get_object_or_404(Club, pk=club_id)

    return render(
        request,
        "tournaments/tournaments.html",
        {
            'future': future[:10],
            'live': live[:10],
            'ended': finished[:10],
            'club': club,
        }
    )

def tournaments_query(query, club_id, ascending):
    queries = [query, Q(is_private=False, is_deleted=False, event__club__isnull=False)]

    club = None
    if club_id:
        club = get_object_or_404(Club, pk=club_id)
        q_club = Q(event__club=club)
        queries.append(q_club)

    sortkey = 'start_date'
    if not ascending:
        sortkey = '-start_date'
    return Tournament.objects.filter(*queries).order_by(sortkey)

def finished_tournaments(club_id):
    ended_tournaments = tournaments_query(Q(end_date__isnull=False), club_id, False)
    return [t for t in ended_tournaments if t.display_tournament()]

def live_tournaments(club_id):
    tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True)
    return [t for t in tournaments if t.display_tournament() and t.supposedly_in_progress()]

def future_tournaments(club_id):
    tomorrow = datetime.now().date() + timedelta(days=1)
    tournaments = tournaments_query(Q(end_date__isnull=True, start_date__gte=tomorrow), club_id, True)
    return [t for t in tournaments if t.display_tournament()]

def tournament_info(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    return render(request, 'tournaments/tournament_info.html', {
        'tournament': tournament,
    })

def tournaments(request):

    filter = int(request.GET.get('filter'))
    club_id = request.GET.get('club')

    title = ''
    tournaments = []
    if filter==0:
        title = 'À venir'
        tournaments = future_tournaments(club_id)
    elif filter==1:
        title = 'En cours'
        tournaments = live_tournaments(club_id)
    elif filter==2:
        title = 'Terminés'
        tournaments = finished_tournaments(club_id)

    return render(
        request,
        "tournaments/tournaments_list.html",
        {
            'tournaments': tournaments,
            'title': title,
            'club': club_id,
        }
    )

def clubs(request):
    all_clubs = Club.objects.all().order_by('name')
    clubs = []
    for club in all_clubs:
        if club.events_count() > 0:
            clubs.append(club)

    return render(request, 'tournaments/clubs.html', {
        'clubs': clubs,
    })

def club(request, club_id):
    club = get_object_or_404(Club, pk=club_id)
    return render(request, 'tournaments/summons.html', {
        'tournament': tournament,
        'team_summons': team_summons,
    })

def tournament(request, tournament_id):

    tournament = get_object_or_404(Tournament, pk=tournament_id)

    round_id = request.GET.get('round')
    group_stage_id = request.GET.get('group_stage')
    match_groups = tournament.match_groups(False, group_stage_id, round_id)


    bracket_rounds = tournament.round_set.filter(parent=None, group_stage_loser_bracket=False).order_by('-index')
    rounds = list(tournament.round_set.filter(group_stage_loser_bracket=True))
    rounds.extend(bracket_rounds)

    group_stages = sorted(tournament.get_computed_group_stage(), key=lambda s: (s.step, s.index))

    if tournament.display_matches() or tournament.display_group_stages():
        return render(request, 'tournaments/matches.html', {
            'tournament': tournament,
            'rounds': rounds,
            'group_stages': group_stages,
            'match_groups': match_groups,
        })
    else:
        return tournament_info(request, tournament_id)

def tournament_teams(request, tournament_id):

    tournament = get_object_or_404(Tournament, pk=tournament_id)
    teams = tournament.teams(True)

    return render(request, 'tournaments/teams.html', {
        'tournament': tournament,
        'teams': teams,
    })

def tournament_summons(request, tournament_id):

    tournament = get_object_or_404(Tournament, pk=tournament_id)
    team_summons = tournament.team_summons()

    return render(request, 'tournaments/summons.html', {
        'tournament': tournament,
        'team_summons': team_summons,
    })

def tournament_broadcasted_summons(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    return render(request, 'tournaments/broadcast/broadcasted_summons.html', {
        'tournament': tournament,
        'qr_code_url': qr_code_url(request, tournament_id),
        'qr_code_options': qr_code_options(),
    })

def tournament_summons_json(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    team_summons = [summon.to_dict() for summon in tournament.team_summons()]
    data = json.dumps(team_summons)
    return HttpResponse(data, content_type='application/json')

def tournament_broadcast_home(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    return render(request, 'tournaments/broadcast/broadcast.html', {
        'tournament': tournament,
        'qr_code_url': qr_code_url(request, tournament_id),
        'qr_code_options': qr_code_options(),
    })

def automatic_broadcast(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    return render(request, 'tournaments/broadcast/broadcasted_auto.html', {
        'tournament': tournament,
        'qr_code_url': qr_code_url(request, tournament_id),
        'qr_code_options': qr_code_options(),
    })

def automatic_broadcast_event(request, event_id):
    event = get_object_or_404(Event, pk=event_id)
    tournaments = Tournament.objects.filter(event=event)
    tournament_ids = [str(tournament.id) for tournament in tournaments]
    return render(request, 'tournaments/broadcast/broadcasted_auto_event.html', {
        'tournament_ids': tournament_ids,
    })

def qr_code_url(request, tournament_id):
    qr_code_url = reverse('tournament', args=[tournament_id])
    return request.build_absolute_uri(qr_code_url)

def qr_code_url_with_query(request, club_id):
    url_with_query = f"{request.build_absolute_uri('/')}?club={str(club_id)}"
    return url_with_query

def qr_code_options():
    return QRCodeOptions(size=10, border=4, error_correction='L')

def tournament_matches(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    return render(request, 'tournaments/broadcast/broadcasted_matches.html', {
        'tournament': tournament,
        'qr_code_url': qr_code_url(request, tournament_id),
        'qr_code_options': qr_code_options(),
    })

def broadcast_json(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    broadcast = tournament.broadcast_content()
    data = json.dumps(broadcast)
    return HttpResponse(data, content_type='application/json')

def tournament_matches_json(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    matches, group_stages = tournament.broadcasted_matches_and_group_stages()
    live_matches = [match.live_match() for match in matches]

    data = json.dumps(live_matches, default=vars)
    return HttpResponse(data, content_type='application/json')

def tournament_group_stages(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    live_group_stages = list(tournament.live_group_stages())
    unique_steps = sorted(set(gs.step for gs in live_group_stages), reverse=True)

    return render(request, 'tournaments/group_stages.html', {
        'tournament': tournament,
        'group_stages': live_group_stages,
        'unique_steps': unique_steps,
    })

def tournament_broadcasted_group_stages(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    return render(request, 'tournaments/broadcast/broadcasted_group_stages.html', {
        'tournament': tournament,
        'qr_code_url': qr_code_url(request, tournament_id),
        'qr_code_options': qr_code_options(),
    })

def tournament_live_group_stage_json(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)

    # Get all live group stages and filter for the last running step
    live_group_stages = [gs.live_group_stages() for gs in tournament.last_group_stage_step()]

    gs_dicts = [gs.to_dict() for gs in live_group_stages]
    data = json.dumps(gs_dicts)
    return HttpResponse(data, content_type='application/json')

def tournament_rankings(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    rankings = tournament.rankings()

    return render(request, 'tournaments/rankings.html', {
        'tournament': tournament,
        'rankings': rankings,
    })

def tournament_rankings_json(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    rankings = tournament.rankings()

    data = json.dumps(rankings, default=vars)
    return HttpResponse(data, content_type='application/json')

def tournament_broadcast_rankings(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    return render(request, 'tournaments/broadcast/broadcasted_rankings.html', {
        'tournament': tournament,
        'qr_code_url': qr_code_url(request, tournament_id),
        'qr_code_options': qr_code_options(),
    })

def players(request):
    return render(request, 'tournaments/test.html')

def activate(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = CustomUser.objects.get(pk=uid)
    except(TypeError, ValueError, OverflowError, CustomUser.DoesNotExist):
        user = None
    if user is not None and account_activation_token.check_token(user, token):
        user.is_active = True
        user.save()
        return HttpResponse('Votre email est confirmé. Vous pouvez maintenant vous connecter.')
    else:
        return HttpResponse('Le lien est invalide.')

def club_broadcast(request, broadcast_code):
    club = get_object_or_404(Club, broadcast_code=broadcast_code)
    q_not_deleted = Q(is_deleted=False, event__club=club)
    tournaments = Tournament.objects.filter(q_not_deleted).order_by('-start_date')

    return render(request, 'tournaments/broadcast/broadcast_club.html', {
        'club': club,
        'tournaments': tournaments,
    })

def club_broadcast_auto(request, broadcast_code):
    club = get_object_or_404(Club, broadcast_code=broadcast_code)
    q_not_deleted = Q(is_deleted=False, event__club=club)
    now = timezone.now().replace(hour=0, minute=0, second=0, microsecond=0)

    recent_time_window = now - timedelta(hours=4)

    tournaments = Tournament.objects.filter(
        q_not_deleted,
        Q(is_private=False),  # Exclude private tournaments
        (
            (
                Q(end_date__isnull=True) &  # Include ongoing tournaments
                (Q(start_date__gte=now - timedelta(days=3)) & Q(start_date__lt=now + timedelta(days=3)))  # Include tournaments that are ongoing and start within 3 days
            ) |
            (Q(end_date__isnull=False) & Q(end_date__gte=recent_time_window))  # Include tournaments finished within the last 4 hours
        )
    )

    tournament_ids = [str(tournament.id) for tournament in tournaments]
    #print(tournament_ids)
    return render(request, 'tournaments/broadcast/broadcasted_auto_event.html', {
        'tournament_ids': tournament_ids,
        'club_name': club.name,
        'qr_code_url': qr_code_url_with_query(request, club.id),
        'qr_code_options': qr_code_options(),

    })

def download(request):
    return render(request, 'tournaments/download.html')

def test_apns(request):
    token = DeviceToken.objects.first()

    asyncio.run(send_push_notification(token.value, 'hello!'))

    return HttpResponse('OK!')

def test_websocket(request):
    return render(request, 'tournaments/test_websocket.html')

def terms_of_use(request):
    return render(request, 'terms_of_use.html')

import pandas as pd
from .utils.extensions import create_random_filename

@csrf_exempt
def xls_to_csv(request):
    if request.method == 'POST':
        # Check if the request has a file
        if 'file' in request.FILES:
            uploaded_file = request.FILES['file']

            # Save the uploaded file
            directory = 'tmp/csv/'
            file_path = os.path.join(directory, uploaded_file.name)
            file_name = default_storage.save(file_path, ContentFile(uploaded_file.read()))

            # convert to csv and save
            data_xls = pd.read_excel(file_name, sheet_name=0, index_col=None)
            csv_file_name = create_random_filename('players', 'csv')
            output_path = os.path.join(directory, csv_file_name)
            data_xls.to_csv(output_path, sep=';', index=False, encoding='utf-8')

            # Send the processed file back
            with default_storage.open(output_path, 'rb') as file:
                response = HttpResponse(file.read(), content_type='application/octet-stream')
                response['Content-Disposition'] = f'attachment; filename="players.csv"'

            # Clean up: delete both files
            default_storage.delete(file_path)
            default_storage.delete(output_path)

            return response
        else:
            return HttpResponse("No file was uploaded", status=400)
    else:
        return HttpResponse("Only POST requests are allowed", status=405)


def simple_form_view(request):

    if request.method == 'POST':
        # If this is a POST request, we need to process the form data
        form = SimpleForm(request.POST)
        if form.is_valid():
            # Process the data in form.cleaned_data
            name = form.cleaned_data['name']
            # Do something with the data (e.g., save to the database)
            send_email_to_jap_list()
            # send_email('laurent@staxriver.com', 'Laurent')
            return HttpResponse(f"Hello, {name}!")  # Simple response with name
    else:
        form = SimpleForm()
        # print(request.method)
        # If this is a GET request, we display an empty form

    return render(request, 'tournaments/admin/mail_test.html', {'form': form})

def send_email_to_jap_list():

    # Open the CSV file
    with open('tournaments/static/misc/jap-test.csv', 'r') as file:
        csv_reader = csv.reader(file)

        def log_error(message):
            with open('email_errors.log', 'a') as log_file:
                timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                log_file.write(f"{timestamp}: {message}\n")

        batch = []
        for row in csv_reader:
            if len(row) >= 4:
                name = row[2]
                mail = row[3]
                batch.append((mail, name))

                if len(batch) == 10:
                    for email, recipient_name in batch:
                        try:
                            send_email(email, recipient_name)
                            print(f"Name: {recipient_name}, mail: {email}")
                        except Exception as e:
                            error_message = f"Error sending email to {email}: {str(e)}"
                            log_error(error_message)
                            print(error_message)

                    batch = []
                    time.sleep(2)
            else:
                print(f"Row doesn't have enough elements: {row}")

        # Send any remaining emails in the last batch
        for email, recipient_name in batch:
            try:
                send_email(email, recipient_name)
                print(f"Name: {recipient_name}, mail: {email}")
            except Exception as e:
                error_message = f"Error sending email to {email}: {str(e)}"
                log_error(error_message)
                print(error_message)


def send_email(mail, name):
    if name.lower() not in mail.lower():
        name = ""

    subject = "Tes tournois en toute simplicité avec Padel Club"
    body = f"Salut {name} !\n\nJe me permets de t'écrire car je suis JAP2 en région PACA et développeur, et je viens de lancer Padel Club, une app iOS qui facilite enfin l'organisation des tournois.\n\nAvec elle, tu peux convoquer rapidement, simuler et programmer tes structures, diffuser tous les résultats à tous les joueurs, et ce depuis un iPhone.\n\nTu peux l'essayer gratuitement pour découvrir tout son potentiel ! Télécharge l'app ici et teste la dès ton prochain tournoi: https://padelclub.app/download/\n\nJe suis disponible pour échanger avec toi par mail ou téléphone au 06 81 59 81 93 et voir ce que tu en penses.\nÀ bientôt j'espère !\n\nRazmig"

    email = EmailMessage(subject, body, to=[mail])
    email.send()

from api.serializers import GroupStageSerializer, MatchSerializer, PlayerRegistrationSerializer, RoundSerializer, TeamRegistrationSerializer, TeamScoreSerializer

@staff_member_required
def tournament_import_view(request):
    if request.method == 'POST':
        zip_file = request.FILES.get('tournament_zip')
        if zip_file:
            try:
                tournament_id = os.path.splitext(zip_file.name)[0]
                tournament = Tournament.objects.get(id=tournament_id)

                # Delete existing relationships
                tournament.round_set.all().delete()
                tournament.groupstage_set.all().delete()
                tournament.teamregistration_set.all().delete()

                with zipfile.ZipFile(zip_file) as z:
                    # First, process rounds
                    rounds_data = get_file_data(z, f"{tournament_id}/rounds.json")
                    if rounds_data:
                        # First pass: Create rounds without parent relationships
                        rounds_without_parent = []
                        for item in rounds_data:
                            item['tournament'] = tournament.id
                            # Temporarily remove parent field
                            parent = item.pop('parent', None)
                            rounds_without_parent.append({'data': item, 'parent': parent})

                        serializer = RoundSerializer(data=[item['data'] for item in rounds_without_parent], many=True)
                        serializer.is_valid(raise_exception=True)
                        created_rounds = serializer.save()

                        # Create a mapping of round IDs
                        round_mapping = {round_obj.id: round_obj for round_obj in created_rounds}

                        # Second pass: Update parent relationships
                        for round_obj, original_data in zip(created_rounds, rounds_without_parent):
                            if original_data['parent']:
                                round_obj.parent = round_mapping.get(original_data['parent'])
                                round_obj.save()

                    # Then process all other files
                    serializer_mapping = {
                        'group-stages.json': GroupStageSerializer,
                        'team-registrations.json': TeamRegistrationSerializer,
                        'matches.json': MatchSerializer,
                        'player-registrations.json': PlayerRegistrationSerializer,
                        'team-scores.json': TeamScoreSerializer
                    }

                    # Process each remaining file
                    for filename, serializer_class in serializer_mapping.items():
                        process_file(z, filename, tournament_id, tournament, serializer_class)

                return JsonResponse({'status': 'success'})

            except Exception as e:
                return JsonResponse({'status': 'error', 'message': str(e)})
    else:
        return render(request, 'tournaments/admin/tournament_cleaner.html')

def process_file(zip_file, filename, tournament_id, tournament, serializer_class):
    """Helper function to process individual files"""
    try:
        file_path = f"{tournament_id}/{filename}"
        json_data = get_file_data(zip_file, file_path)

        if json_data:
            # Add tournament to each item
            for item in json_data:
                item['tournament'] = tournament.id

            serializer = serializer_class(data=json_data, many=True)
            serializer.is_valid(raise_exception=True)
            serializer.save()

    except Exception as e:
        print(f"Error processing {filename}: {str(e)}")

def get_file_data(zip_file, file_path):
    """Helper function to read and parse JSON data from zip file"""
    try:
        file_content = zip_file.read(file_path)
        return json.loads(file_content)
    except KeyError:
        print(f"File not found: {file_path}")
        return None
    except json.JSONDecodeError as e:
        print(f"JSON Error for {file_path}: {str(e)}")
        raise Exception(f"Invalid JSON in file {file_path}")

def team_details(request, tournament_id, team_id):
    tournament = get_object_or_404(Tournament, id=tournament_id)
    team = get_object_or_404(TeamRegistration, id=team_id)
    print(f"Processing team {team_id} in tournament {tournament_id}")

    # Get all matches for this team
    all_matches = team.get_matches()
    print(f"Total matches found: {all_matches.count()}")
    print("Match details:")
    for match in all_matches:
        print(f"- Match {match.id}: start={match.start_date}, end={match.end_date}")

    return render(request, 'tournaments/team_details.html', {
        'tournament': tournament,
        'team': team,
        'debug': True  # Set to False in production
    })
