# Standard library imports
import os
import csv

from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse, HttpResponse
from django.utils.encoding import force_str
from django.utils.http import urlsafe_base64_decode
from django.urls import reverse
from django.conf import settings
from django.db import transaction

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 django.views.generic import View
from django.db.models import Q
from django.template import loader

from tournaments.models.device_token import DeviceToken

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

from datetime import date
import json
import time
import asyncio
from datetime import date, datetime, timedelta
import csv
import zipfile

from api.tokens import account_activation_token

# Third-party imports
from qr_code.qrcode.utils import QRCodeOptions

# Django imports
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse, JsonResponse, Http404
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.utils.encoding import force_str, force_bytes
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template import loader
from django.template.loader import render_to_string
from django.contrib import messages
from django.contrib.sites.shortcuts import get_current_site
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import (
    UserCreationForm,
    SetPasswordForm,
)
from django.contrib.auth.views import PasswordResetConfirmView
from django.contrib.auth import get_user_model
from django.contrib.auth.tokens import default_token_generator
from django.db.models import Q
from django.views.decorators.csrf import csrf_exempt
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.core.mail import EmailMessage
from django.views.decorators.csrf import csrf_protect
from .services.tournament_registration import TournamentRegistrationService
from .services.tournament_unregistration import TournamentUnregistrationService
from django.core.exceptions import ValidationError


# Local application imports
from .models import (
    Court,
    DateInterval,
    Club,
    Tournament,
    CustomUser,
    Event,
    Round,
    GroupStage,
    Match,
    TeamScore,
    TeamRegistration,
    PlayerRegistration,
    Purchase,
    FailedApiCall,
    TeamSummon,
    FederalCategory,
    UnregisteredTeam,
    UnregisteredPlayer
)
from .forms import (
    SimpleForm,
    SimpleCustomUserCreationForm,
    TournamentRegistrationForm,
    AddPlayerForm,
    ProfileUpdateForm,
)
from .utils.apns import send_push_notification
from .utils.licence_validator import LicenseValidator
from .utils.player_search import get_player_name_from_csv
from api.tokens import account_activation_token
from tournaments.models.device_token import DeviceToken
from tournaments.models.player_enums import PlayerDataSource, PlayerSexType
from django.views.generic.edit import UpdateView
from .forms import CustomPasswordChangeForm

def index(request):
    now = timezone.now()
    thirty_days_ago = now - timedelta(days=30)
    thirty_days_future = now + timedelta(days=30)

    club_id = request.GET.get('club')
    if club_id:
        tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True, 50)
    else:
        tournaments = tournaments_query(Q(end_date__isnull=True, start_date__gte=thirty_days_ago, start_date__lte=thirty_days_future), club_id, True, 50)

    display_tournament = [t for t in tournaments if t.display_tournament()]
    live = []
    future = []
    for t in display_tournament:
        if t.supposedly_in_progress():
            live.append(t)
        elif t.starts_in_the_future():
            future.append(t)
    clean_ended_tournaments = tournaments_query(Q(end_date__isnull=False), club_id, False, 50)
    clean_ended_tournaments = [t for t in clean_ended_tournaments if t.display_tournament()]
    ended_tournaments = [t for t in display_tournament if t.should_be_over()]

    # Combine both lists
    finished = clean_ended_tournaments + ended_tournaments

    # Sort the combined list by start_date in descending order
    finished.sort(key=lambda t: t.start_date, reverse=True)

    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, limit=None):
    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'

    queryset = Tournament.objects.filter(*queries).prefetch_related(
        'group_stages',
        'rounds',
        'team_registrations',
    ).order_by(sortkey)

    # Apply limit directly in the database query
    if limit is not None and isinstance(limit, int) and limit > 0:
        queryset = queryset[:limit]

    return queryset

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

    one_day_ago = timezone.now() - timedelta(days=1)
    ended_tournaments = tournaments_query(
        Q(end_date__isnull=True, start_date__lt=one_day_ago),
        club_id,
        False,
        limit
    )
    ended_tournaments = [t for t in ended_tournaments if t.display_tournament() and t.should_be_over()]

    # Combine both lists
    all_tournaments = clean_ended_tournaments + ended_tournaments

    # Sort the combined list by start_date in descending order
    all_tournaments.sort(key=lambda t: t.start_date, reverse=True)

    return all_tournaments

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

def future_tournaments(club_id, limit=None):
    tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True, limit)
    return [t for t in tournaments if t.display_tournament() and t.starts_in_the_future()]

def tournament_info(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    registered_user = None
    team_registration = None
    is_captain = False
    player_register_check = None

    if request.user.is_authenticated:
        # Assuming user's licence_id is stored in the user profile (e.g., request.user.licence_id)
        user_licence_id = request.user.licence_id
        player_register_check = tournament.player_register_check(user_licence_id)
        if user_licence_id is not None and player_register_check is None:
            validator = LicenseValidator(user_licence_id)
            stripped_license = validator.stripped_license
            # Check if there is a PlayerRegistration for this user in this tournament
            registered_user = PlayerRegistration.objects.filter(
                licence_id__icontains=stripped_license,
                team_registration__tournament=tournament,
                team_registration__walk_out=False,
            ).first()

        # If the user is registered, retrieve their team registration
        if registered_user:
            is_captain = registered_user.captain
            team_registration = registered_user.team_registration

    return render(request, 'tournaments/tournament_info.html', {
        'tournament': tournament,
        'team': team_registration,
        'is_captain': is_captain,
        'player_register_check': player_register_check
    })


def tournaments(request):
    filter_param = request.GET.get('filter')
    filter = None

    if filter_param:
        try:
            filter = int(filter_param)
            if filter not in [0, 1, 2]:  # Valid filter values
                return redirect('/')

        except:
            return redirect('/')

    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.rounds.filter(parent=None, group_stage_loser_bracket=False).order_by('-index')
    rounds = list(tournament.rounds.filter(group_stage_loser_bracket=True))
    rounds.extend(bracket_rounds)

    group_stages = sorted(tournament.sorted_group_stages(), 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)
    selected_teams = [team for team in teams if team.stage != "Attente"]
    waiting_teams = [team for team in teams if team.stage == "Attente"]

    return render(request, 'tournaments/teams.html', {
        'tournament': tournament,
        'selected_teams': selected_teams,
        'waiting_teams': waiting_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_dicts = [match.live_match().to_dict() for match in matches]
    data = json.dumps(live_matches_dicts, default=vars)
    return HttpResponse(data, content_type='application/json')

def tournament_prog_json(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    matches = tournament.broadcasted_prog()

    # Convert matches to JSON-serializable format, handling None/empty slots
    live_matches = []
    for match in matches:
        if match is None or isinstance(match, dict) and match.get('empty'):
            live_matches.append({"empty": True})
        else:
            live_matches.append(match.live_match().to_dict())

    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_broadcasted_prog(request, tournament_id):
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    return render(request, 'tournaments/broadcast/broadcasted_prog.html', {
        'tournament': tournament,
        'qr_code_url': qr_code_url(request, tournament_id),
        'qr_code_options': qr_code_options(),
    })

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


def tournament_bracket_json(request, tournament_id):
    """
    JSON endpoint for tournament bracket data.
    """
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    context = get_butterfly_bracket_view_context(tournament, parent_round=None, double_butterfly_mode=True, display_loser_final=True)

    data = {
        'match_groups': [match_group.to_dict() for match_group in context['match_groups']],
        'double_butterfly_mode': context['double_butterfly_mode'],
        'display_loser_final': context['display_loser_final']
    }

    return JsonResponse(data)


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()

        # Specify the authentication backend when logging in
        from django.contrib.auth import login
        login(request, user, backend='django.contrib.auth.backends.ModelBackend')

        return redirect('activation_success')
    else:
        # Redirect to a custom error page
        return redirect('activation_failed')  # Define this URL in your urls.py

def activation_success(request):
    return render(request, 'registration/activation_success.html')

def activation_failed(request):
    return render(request, 'registration/activation_failed.html')

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):

    user = CustomUser.objects.filter(username='laurent').first()
    for device_token in user.device_tokens.all():
        asyncio.run(send_push_notification(device_token.value, 'LOL?!'))

    # token = DeviceToken.objects.first()

    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()))

            # Check available sheets and look for 'inscriptions'
            xls = pd.ExcelFile(file_name)
            sheet_names = xls.sheet_names

            # Determine which sheet to use
            target_sheet = 0  # Default to first sheet
            if 'inscriptions' in [name.lower() for name in sheet_names]:
                for i, name in enumerate(sheet_names):
                    if name.lower() == 'inscriptions':
                        target_sheet = i  # or use the name directly: target_sheet = name
                        break

            # Convert to csv and save
            data_xls = pd.read_excel(file_name, sheet_name=target_sheet, 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()

def signup(request):
    next_url = request.GET.get('next', '/')

    if request.method == 'POST':
        form = SimpleCustomUserCreationForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.is_active = False
            user.origin = UserOrigin.SITE
            user.save()

            if not settings.DEBUG:
                send_verification_email(request, user, next_url)

            return render(request, 'registration/signup_success.html', {
                'next_url': next_url,
                'user_email': user.email  # Add the user's email to the context
            })
    else:
        form = SimpleCustomUserCreationForm()

    response = render(request, 'registration/signup.html', {'form': form})
    return response

def send_verification_email(request, user, next_url):
    print('next_url', next_url)

    current_site = get_current_site(request)
    mail_subject = 'Activez votre compte Padel Club !'
    # Prepare the email subject and message
    message = render_to_string('tournaments/acc_active_email.html', {
        'user': user,
        'domain': current_site.domain,
        'uid': urlsafe_base64_encode(force_bytes(user.pk)),
        'token': account_activation_token.make_token(user),
        'next': next_url,  # Pass next URL to the template
    })

    email = EmailMessage(mail_subject, message, to=[user.email])
    email.content_subtype = "html"
    email.send()

@login_required
def profile(request):
    user = request.user  # Get the currently authenticated user
    return render(request, 'registration/profile.html', {
        'user_name': user.username
    })

@csrf_protect
def register_tournament(request, tournament_id):
    tournament = get_object_or_404(Tournament, id=tournament_id)
    service = TournamentRegistrationService(request, tournament)
    service.initialize_context()
    print("initialize_context")
    if request.method == 'POST':
        service.handle_post_request()
    else:
        service.handle_get_request()

    return render(request, 'register_tournament.html', service.context)

@login_required
def unregister_tournament(request, tournament_id):
    tournament = get_object_or_404(Tournament, id=tournament_id)
    service = TournamentUnregistrationService(request, tournament)

    if not service.can_unregister():
        return redirect('tournament-info', tournament_id=tournament_id)

    service.process_unregistration()
    return redirect('tournament-info', tournament_id=tournament_id)

class CustomPasswordResetConfirmView(PasswordResetConfirmView):
    template_name = 'registration/password_reset_confirm.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['custom_message'] = "Veuillez entrer un nouveau mot de passe."
        return context

    def form_valid(self, form):
        response = super().form_valid(form)
        return response

    def get_user(self, uidb64):
        """
        Override this method to decode the uid and return the corresponding user.
        """
        try:
            # Use get_user_model() instead of direct User import
            User = get_user_model()

            uid = urlsafe_base64_decode(uidb64).decode()
            user = User.objects.get(pk=uid)
            return user
        except (TypeError, ValueError, User.DoesNotExist):
            raise Http404("User not found")

@login_required
def my_tournaments(request):
    user = request.user
    user_licence_id = request.user.licence_id

    # If no licence_id, return empty lists
    if user_licence_id is None:
        return render(request, 'registration/my_tournaments.html', {
            'upcoming_tournaments': [],
            'running_tournaments': [],
            'ended_tournaments': [],
            'user_name': user.username
        })

    # Get all tournaments for the user based on their licence
    validator = LicenseValidator(user_licence_id)
    stripped_license = validator.stripped_license

    def filter_user_tournaments(tournaments):
        return [t for t in tournaments if t.team_registrations.filter(
            player_registrations__licence_id__icontains=stripped_license,
            walk_out=False
        ).exists()]

    # Get filtered tournaments using the helper function
    upcoming_tournaments = filter_user_tournaments(future_tournaments(None))
    running_tournaments = filter_user_tournaments(live_tournaments(None))
    ended_tournaments = filter_user_tournaments(finished_tournaments(None))

    return render(request, 'registration/my_tournaments.html', {
        'upcoming_tournaments': upcoming_tournaments,
        'running_tournaments': running_tournaments,
        'ended_tournaments': ended_tournaments,
        'user_name': user.username
    })

from django.contrib.auth.mixins import LoginRequiredMixin

class ProfileUpdateView(LoginRequiredMixin, UpdateView):
    model = CustomUser
    form_class = ProfileUpdateForm
    template_name = 'profile.html'
    success_url = reverse_lazy('profile')
    login_url = '/login/'  # Specify where to redirect if user is not logged in

    def get_object(self, queryset=None):
        return self.request.user

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['password_change_form'] = CustomPasswordChangeForm(user=self.request.user)
        return context


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:
            print('yes')

            try:
                tournament_id = os.path.splitext(zip_file.name)[0]
                tournament = Tournament.objects.get(id=tournament_id)

                # Delete existing relationships
                print('round delete')

                rounds = Round.objects.filter(tournament=tournament,parent=None)
                for round in rounds:
                    round.delete_dependencies()
                for gs in tournament.group_stages.all():
                    gs.delete_dependencies()
                for tr in tournament.team_registrations.all():
                    tr.delete_dependencies()

                # with transaction.atomic():
                #     for round in tournament.rounds.all():
                #         round.delete()
                tournament.rounds.all().delete()
                tournament.group_stages.all().delete()
                tournament.team_registrations.all().delete()
                # tournament.player_registrations.all().delete()
                # tournament.matches.all().delete()
                # tournament.team_scores.all().delete()

                print(f'round count = {tournament.rounds.count()}')
                print(f'group_stages count = {tournament.group_stages.count()}')
                print(f'team_registrations count = {tournament.team_registrations.count()}')

                print(f'PR count = {PlayerRegistration.objects.count()}')
                print(f'TS count = {TeamScore.objects.count()}')
                print(f'M count = {Match.objects.count()}')

                with zipfile.ZipFile(zip_file) as z:
                    # First, process rounds
                    rounds_data = get_file_data(z, f"{tournament_id}/rounds.json")
                    # print(f'rounds count = {len(rounds_data)}')

                    if rounds_data:
                        # First pass: Create rounds with preserved UUIDs
                        for item in rounds_data:
                            # print('round #1 create')
                            item['tournament'] = tournament.id
                            round_id = item['id']  # Preserve the original UUID
                            Round.objects.create(
                                id=round_id,
                                tournament_id=tournament.id,
                                index=item['index'],
                                format=item.get('format'),
                                start_date=item.get('start_date'),
                                group_stage_loser_bracket=item.get('group_stage_loser_bracket', False),
                                loser_bracket_mode=item.get('loser_bracket_mode', 0)
                            )

                        # Second pass: Set parent relationships
                        for item in rounds_data:
                            # print('round #2 set parent')

                            if item.get('parent'):
                                round_obj = Round.objects.get(id=item['id'])
                                round_obj.parent_id = item['parent']
                                round_obj.save()

                    # Then process all other files
                    serializer_mapping = {
                        # 'rounds.json': RoundSerializer,
                        '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:
                print(f'error = {str(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:
        print(f'process {filename}')
        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:
                # print(f'process {item}')
                item['tournament'] = tournament.id
                item['store_id'] = str(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 status_page(request):
    return render(request, 'tournaments/admin/status.html')

def team_details(request, tournament_id, team_id):
    # First check if team_id is None or invalid
    if team_id is None or team_id == 'None':
        # Redirect to tournament page or show an error
        return redirect('tournament-info', tournament_id=tournament_id)

    tournament = get_object_or_404(Tournament, id=tournament_id)
    try:
        team = get_object_or_404(TeamRegistration, id=team_id)
    except (ValueError, ValidationError):
        # Handle invalid UUID
        return redirect('tournament-info', tournament_id=tournament_id)

    # Get all matches for this team
    all_matches = team.get_matches()

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

def tournament_bracket(request, tournament_id):
    """
    View to display tournament bracket structure.
    """
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    context = get_butterfly_bracket_view_context(tournament, parent_round=None, double_butterfly_mode=False, display_loser_final=True)
    return render(request, 'tournaments/tournament_bracket.html', context)

def round_bracket(request, tournament_id, round_id):
    """
    View to display round bracket structure.
    """
    tournament = get_object_or_404(Tournament, pk=tournament_id)
    round = get_object_or_404(Round, pk=round_id)
    context = get_butterfly_bracket_view_context(tournament, round, double_butterfly_mode=False, display_loser_final=False)
    return render(request, 'tournaments/tournament_bracket.html', context)

def get_butterfly_bracket_view_context(tournament, parent_round=None, double_butterfly_mode=False, display_loser_final=True):
    if parent_round:
        double_butterfly_mode = False
        display_loser_final = True

    serializable_match_groups = tournament.get_butterfly_bracket_match_group(parent_round, double_butterfly_mode, display_loser_final)

    context = {
        'tournament': tournament,
        'match_groups': serializable_match_groups,
        'double_butterfly_mode': double_butterfly_mode,
        'display_loser_final': display_loser_final
    }

    return context

def tournament_prog(request, tournament_id):
    tournament = get_object_or_404(Tournament, id=tournament_id)

    # Get matches from all_groups
    match_groups = tournament.all_groups(broadcasted=False)

    # Flatten matches and add necessary attributes
    all_matches = []
    for group in match_groups:
        for match in group.matches:
            if match.start_date:  # Only include matches with start dates
                all_matches.append({
                    'start_date': match.start_date,
                    'court_index': match.court_index,
                    # Add other match attributes needed for match_cell.html
                    'match': match
                })

    # Sort matches by date and court
    all_matches.sort(key=lambda x: (x['start_date'], x['court_index'] or 999))

    context = {
        'tournament': tournament,
        'match_groups': {'matches': all_matches}
    }
    return render(request, 'tournaments/prog.html', context)

def custom_logout(request):
    from django.contrib.auth import logout
    logout(request)
    return redirect('index')  # or whatever URL you want to redirect to

class UserListExportView(LoginRequiredMixin, View):
    def get(self, request, *args, **kwargs):
        users = CustomUser.objects.order_by('date_joined')

        # Prepare the response
        response = HttpResponse(content_type='text/plain; charset=utf-8')

        # Write header
        headers = [
            'Prenom', 'Nom', 'Club', 'Email', 'Telephone', 'Username',
            'Origine', 'Actif', 'Inscription', 'Tournois'
        ]
        response.write('\t'.join(headers) + '\n')

        # Write data rows
        for user in users:
            row = [
                str(user.first_name or ''),
                str(user.last_name or ''),
                str(user.latest_event_club_name() or ''),
                str(user.email or ''),
                str(user.phone or ''),
                user.username,
                str(user.get_origin_display()),
                'Oui' if user.is_active else 'Non',
                user.date_joined.strftime('%Y-%m-%d %H:%M:%S'),
                str(user.event_count())
            ]
            # Replace any tabs or newlines in the data to prevent formatting issues
            row = [field.replace('\t', ' ') for field in row]
            response.write('\t'.join(row) + '\r\n')

        return response
