#views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse, JsonResponse, HttpResponseForbidden
from django.template import loader
from django.template.loader import render_to_string
from .forms import CustomUserCreationForm, UpdateProfileForm, CustomAuthenticationForm
from .models import Event, TipBilet, Bilet, Comanda, ContorComenzi, UserFile #,Chitanta
from ticknex.utils.email_utils import trimite_email_bilet, trimite_email_comanda, trimite_email_plasare_comanda
from django.db.models import Q, Max, Sum, F, DecimalField, ExpressionWrapper
from django.db import transaction
from django.urls import reverse
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_POST, require_GET
from django.views.decorators.csrf import csrf_exempt
from django.contrib import messages
from django.contrib.auth import update_session_auth_hash
from django.utils.safestring import mark_safe
from django.utils.timezone import now, timedelta
from django.utils import timezone
from django.conf import settings
from django.core.paginator import Paginator
from django.core.files import File
from django.db.models.functions import TruncDate
from datetime import datetime
from collections import defaultdict
from xhtml2pdf import pisa
from django.core.files.base import ContentFile
import qrcode
from io import BytesIO
from decimal import Decimal, ROUND_HALF_UP
import base64
import requests
import json
import uuid
import time
import stripe
import logging
import os
import sys
import traceback


# trebuie să fie înainte de orice import weasyprint
os.environ['LD_LIBRARY_PATH'] = '/lib64:' + os.environ.get('LD_LIBRARY_PATH', '')

import weasyprint

logger = logging.getLogger(__name__)


#CHEIE STRIPE
stripe.api_key = settings.STRIPE_SECRET_KEY
# Create your views here.

#functii terta

def genereaza_pdf_bilet(bilet_id):
    log_path = "/home/biletisr/biletis/stderr.log"
    try:
        bilet = get_object_or_404(
            Bilet.objects.select_related('tip_bilet__event__organizator'),
            id=bilet_id
        )

        # 🔹 QR code
        qr_data = bilet.get_qr_data()
        qr = qrcode.make(qr_data)
        buffer = BytesIO()
        qr.save(buffer, format="PNG")
        qr_base64 = base64.b64encode(buffer.getvalue()).decode()

        # 🔹 Render HTML
        context = {
            'bilet': bilet,
            'qr_base64': qr_base64,
        }


        html_string = render_to_string('participant/bilet_pdf.html', context)

        # 🔹 Generează PDF în memorie (nu pe disk)
        pdf_file = weasyprint.HTML(
            string=html_string,
            base_url=os.path.join(settings.BASE_DIR, 'static')
        ).write_pdf()

        # 🔹 Suprascrie PDF existent sau creează unul nou
        if bilet.pdf:
            bilet.pdf.delete(save=False)  # Șterge vechiul fișier fără a salva modelul
        bilet.pdf.save(
            f"{bilet.nr_serie}.pdf",
            ContentFile(pdf_file),
            save=True
        )

        return bilet.pdf.url
    except Exception as e:
        # 🔹 Log în fișier fix
        exc_type, exc_value, exc_tb = sys.exc_info()
        tb_str = ''.join(traceback.format_exception(exc_type, exc_value, exc_tb))

        with open(log_path, "a") as f:
            f.write(f"\n===== Eroare WeasyPrint pentru Bilet {bilet_id} =====\n")
            f.write(tb_str)
            f.write("\n")

        # 🔹 De asemenea afișează în stderr
        print(f"Eroare WeasyPrint pentru Bilet {bilet_id}: {e}", file=sys.stderr)
        return None



def verifica_disponibilitate_bilete(bilete_list):
    """
    Verifică dacă există suficiente bilete pentru lista de bilete.
    bilete_list: lista de dict-uri cu {"tip_id": id, "nume": ..., "email": ...}
    Returnează (True, None) dacă sunt disponibile toate, sau (False, mesaj) dacă e sold out.
    """
    from collections import Counter

    # 1️⃣ Număr bilete cerute pe tip
    cereri_pe_tip = Counter()
    for b in bilete_list:
        cereri_pe_tip[b['tip_id']] += 1

    # 2️⃣ Verificăm pentru fiecare TipBilet
    for tip_id, cerute in cereri_pe_tip.items():
        try:
            tip = TipBilet.objects.get(id=tip_id)
        except TipBilet.DoesNotExist:
            return False, f"Tip bilet {tip_id} nu există"

        disponibile = tip.nr_maxim - tip.nr_vandute
        if cerute > disponibile:
            return False, f"Sold out: {tip.nume} mai sunt doar {disponibile} bilete"

    return True, None

def expirare_comenzi_rezervate(event):
    """
    Verifică toate comenzile cu status 'rezervata' și, dacă au trecut
    mai mult de 15 minute de la creare, le marchează ca 'anulata' 
    și scade nr_vandute pentru tipurile de bilete rezervate.
    """
    for com in Comanda.objects.filter(eveniment=event, status='rezervata'):
        with transaction.atomic():
            if hasattr(com, 'rezervata_pana') and com.rezervata_pana and timezone.now() > com.rezervata_pana:
                # readucem nr_vandute la starea corecta
                for b in com.bilete:
                    tip = TipBilet.objects.filter(id=b["tip_id"]).first()
                    if tip:
                        tip.nr_vandute = max(tip.nr_vandute - 1, 0)
                        tip.save()
                com.status = 'anulata'
                com.save()


#viewuri
  
#view index
def index(request):
    return render(request, "index.html")

#register - login - logout
def register_view(request):
    if request.user.is_authenticated:
        return redirect('dashboard')  # sau pagina principală pentru user logat

    if request.method == 'POST':
        form = CustomUserCreationForm(request.POST)
        if form.is_valid():
            user = form.save(commit=False)
            user.role = 'participant'  # sau orice rol vrei
            user.save()

            messages.success(request, mark_safe(
                'Contul a fost creat cu succes! '
                '<a href="/login" class="alert-link">Autentifică-te aici</a>.'
            ))
            return redirect('login')  # redirect imediat după creare cont
        else:
            # Mesaj generic de eroare optional, validările sunt în form
            messages.error(request, "Te rog corectează erorile din formular.")
    else:
        form = CustomUserCreationForm()

    return render(request, 'register.html', {'form': form})

def login_view(request):
    if request.user.is_authenticated:
        return redirect('dashboard')
    if request.method == 'POST':
        form = CustomAuthenticationForm(request, data=request.POST)
        if form.is_valid():
            user = form.get_user()
            login(request, user)

            if not request.POST.get('remember_me'):
                # sesiunea expiră când închizi browserul
                request.session.set_expiry(0)
            else:
                # sesiunea persistă 7 zile
                request.session.set_expiry(60 * 60 * 24 * 7)
            return redirect('dashboard')
    else:
        form = CustomAuthenticationForm()
    return render(request, 'login.html', {'form': form})

def logout_view(request):
    if not request.user.is_authenticated:
        return redirect('login')
    if request.method == "POST":
        logout(request)
        messages.success(request, "Te-ai deconectat cu succes.")
        return redirect("login")
    return render(request, "logout_confirm.html")


#view pentru contul-meu
@login_required(login_url='login')
def cont(request):
    user = request.user
    
    if request.method == 'POST':
        profile_form = UpdateProfileForm(request.POST or None, instance=user, user=user)
        password_form = PasswordChangeForm(user, request.POST)

        if 'update_profile' in request.POST and profile_form.is_valid():
            profile_form.save()
            messages.success(request, "Datele contului au fost actualizate.")
            return redirect('cont')

        elif 'change_password' in request.POST and password_form.is_valid():
            user = password_form.save()
            update_session_auth_hash(request, user)  # păstrează sesiunea activă
            messages.success(request, "Parola a fost schimbată cu succes.")
            return redirect('cont')

    else:
        profile_form = UpdateProfileForm(instance=user, user=user)
        password_form = PasswordChangeForm(user)

    return render(request, 'cont.html', {
        'profile_form': profile_form,
        'password_form': password_form,
        'user' : user
    })

#view dashboard

@login_required(login_url='login')
def dashboard_view(request):
    user = request.user

    if user.role == 'organizator':
        evenimente = Event.objects.filter(
            organizator=user,
            finalizat=False
        ).order_by('-data')
        return render(request, 'organizator/dashboard.html', {'evenimente': evenimente})
    else:
        user_email = request.user.email

        # Bilete asociate cu utilizatorul logat (după email), care sunt încă active
        bilete = Bilet.objects.select_related('tip_bilet__event').filter(
            email_participant=user_email, folosit=False
        ).order_by('-tip_bilet__event__data')

        return render(request, 'participant/dashboard.html', {
            'bilete': bilete,
            'user':user
        })

# view pagina admin event

def eveniment_prezentare(request, slug):
    event = get_object_or_404(Event, slug=slug)

    expirare_comenzi_rezervate(event=event)
    if event.finalizat or not event.public:
        return redirect('/evenimente')

    tipuri_bilete = TipBilet.objects.filter(event=event, de_vanzare=True).order_by("pret")

    # 🆕 Calculăm nr de bilete rămase pentru fiecare tip
    for tip in tipuri_bilete:
        tip.nr_ramase = max(tip.nr_maxim - tip.nr_vandute, 0)

    if request.method == "POST":
        selectii = {}
        total_bilete = 0
        for tip in tipuri_bilete:
            cantitate = int(request.POST.get(f"bilete_{tip.id}", 0))
            if cantitate > 0:
                selectii[tip.id] = cantitate
                total_bilete += cantitate

        # Validare bilete selectate
        if total_bilete == 0:
            context = {
                "event": event,
                "tipuri_bilete": tipuri_bilete,
                "eroare": "Trebuie să selectați cel puțin un bilet."
            }
            return render(request, "eveniment_prezentare.html", context)

        if total_bilete > 4:
            context = {
                "event": event,
                "tipuri_bilete": tipuri_bilete,
                "eroare": "Maxim 4 bilete pe comandă."
            }
            return render(request, "organizator/events/prezentare.html", context)

        request.session['selectii_bilete'] = selectii
        return redirect('checkout', slug=slug)

    # GET
    return render(request, "organizator/events/prezentare.html", {
        "event": event,
        "tipuri_bilete": tipuri_bilete,
        "taxa_organizator": event.organizator.taxa_organizator,
        "procent_taxa": event.organizator.procent_taxa,
    })




#view pagina editare event

def eveniment_dashboard(request, slug):
    event = get_object_or_404(Event, slug=slug)
    tipuri_bilete = event.tipuri_bilete.all()
    if not request.user.is_authenticated or request.user != event.organizator:
        return redirect("/")
    
        # Verificăm dacă poate fi șters vreun bilet
    poate_sterge = True
    for tip in tipuri_bilete:
        if tip.nr_vandute > 0:
            poate_sterge = False
            break
    print(poate_sterge)
    
    if request.method == 'POST':
        event.nume = request.POST.get('nume')
        event.descriere = request.POST.get('descriere')
        event.locatie = request.POST.get('locatie')
        event.data = request.POST.get('data')
        event.public = 'public' in request.POST
        event.finalizat = 'finalizat' in request.POST

        if 'imagine' in request.FILES:
            event.imagine = request.FILES['imagine']

        event.save()
        messages.success(request, 'Evenimentul a fost actualizat!')
        return redirect('eveniment_dashboard', slug=event.slug)

    return render(request, 'organizator/events/event_config.html', {'event': event, 'bilete': tipuri_bilete, 'poate_sterge':poate_sterge})

@login_required
@require_POST
def sterge_event(request, id):
    try:
        with transaction.atomic():
            event = get_object_or_404(Event,id=id)
            event.delete()
            messages.success(request, "Evenimentul a fost sters cu succes!")

        return JsonResponse({'status': 'success', 'message': 'Evenimentul a fost șters cu succes.'})
    
    except Event.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': 'Evenimentul nu a fost găsit.'}, status=404)

def recalculeaza_intervale_tipuri_bilete(event):
    """
    Recalculează intervalele pentru toate tipurile de bilete ale unui eveniment.
    Ordinea este determinată de id (ordinea creării).
    """
    current = 1
    tipuri = event.tipuri_bilete.all().order_by('id')  # ordinea creării

    for tip in tipuri:
        tip.interval_start = current
        tip.interval_end = current + tip.nr_maxim - 1
        tip.ultimul_nr_alocat = tip.interval_start - 1  # încă nu s-a vândut nimic
        tip.save()
        current = tip.interval_end + 1

#view adaugare tipuri de bilete
@login_required
def adauga_bilet_ajax(request, slug):
    if request.method == 'POST':
        event = get_object_or_404(Event, slug=slug)

        #Verificare autor
        if event.organizator != request.user:
            return HttpResponseForbidden("Nu ai permisiunea să modifici acest eveniment.")

        nume = request.POST.get('nume')
        pret = request.POST.get('pret')
        nr_maxim = request.POST.get('nr_maxim')
        serie = request.POST.get('serie')
        de_vanzare = request.POST.get('de_vanzare') == 'on'

        if nume and pret and nr_maxim:
            TipBilet.objects.create(event=event, nume=nume, pret=pret, nr_maxim=nr_maxim, de_vanzare=de_vanzare, serie=serie)
            
            #recalculăm intervalele
            recalculeaza_intervale_tipuri_bilete(event)

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

    
#view stergere tipuri de bilete

@login_required
@require_POST
def sterge_tip_bilet(request, pk):
    tip_bilet = get_object_or_404(TipBilet, pk=pk, event__organizator=request.user)

    # Ștergem tipul bilet
    tip_bilet.delete()

    # 🔥 recalculăm intervalele
    recalculeaza_intervale_tipuri_bilete(tip_bilet.event)
    
    return JsonResponse({'status': 'success'})

#view editare tip bilet

@login_required
def editeaza_tip_bilet(request, pk):
    tip = get_object_or_404(TipBilet, pk=pk, event__organizator=request.user)

    if request.method == 'POST':
        tip.nume = request.POST.get('nume')
        tip.pret = request.POST.get('pret')
        tip.nr_maxim = request.POST.get('nr_maxim')
        tip.serie = request.POST.get('serie')
        tip.de_vanzare = request.POST.get('de_vanzare') == 'on'
        tip.save()
        messages.success(request, "Tipul de bilet a fost actualizat cu succes.")
    else:
        messages.error(request, "Cerere invalidă.")

    return redirect('eveniment_dashboard', slug=tip.event.slug)

#view afisare lista tipuri de bilete

@login_required
def lista_bilete_partial(request, slug):
    event = get_object_or_404(Event, slug=slug)

    if event.organizator != request.user:
        return HttpResponseForbidden("Nu ai permisiunea să vezi lista.")
    
    bilete = TipBilet.objects.filter(event=event)
    # verificăm dacă există bilete vândute
    

    return render(
        request,
        'organizator/events/bilete_partial.html',
        {
            'bilete': bilete,
        }
    )

# view creare event

@login_required(login_url='login')
def creeaza_eveniment(request):
    if request.method == 'POST':
        nume = request.POST.get('nume')
        descriere = request.POST.get('descriere')
        locatie = request.POST.get('locatie')
        data = request.POST.get('data')
        imagine = request.FILES.get('imagine')
        public = 'public' in request.POST

        eveniment = Event(
            nume=nume,
            descriere=descriere,
            locatie=locatie,
            data=data,
            imagine=imagine,
            public=public,
            organizator=request.user
        )
        eveniment.save()
        return redirect('dashboard')

    return redirect('dashboard')

# view evenimente finalizate
def evenimente_trecute(request):
    user = request.user
    evenimente = Event.objects.filter(
        organizator=user,
        finalizat=True
    ).order_by('-data')  # cele mai recente primele

    return render(request, 'organizator/evenimente_trecute.html', {'evenimente': evenimente})


#view listare evenimente

def lista_evenimente(request):
    query = request.GET.get('q', '')
    evenimente = Event.objects.filter(public=True, finalizat=False)

    if query:
        evenimente = evenimente.filter(
            Q(nume__icontains=query) | Q(descriere__icontains=query)
        )

    return render(request, 'evenimente.html', {'evenimente': evenimente, 'query': query})

#view adaugare bilete vandute

@login_required
@require_POST
def adauga_bilet_vandut(request, slug):
    event = get_object_or_404(Event, slug=slug, organizator=request.user)
    tip_bilet_id = request.POST.get("tip_bilet")
    nume = request.POST.get("nume_participant")
    email = request.POST.get("email_participant")

    if not nume or not email:
        return JsonResponse({'status': 'error', 'message': 'Toate câmpurile sunt obligatorii.'}, status=400)

    try:
        with transaction.atomic():
            tip = TipBilet.objects.select_for_update().get(id=tip_bilet_id, event=event)

            if tip.nr_vandute >= tip.nr_maxim:
                return JsonResponse({'status': 'error', 'message': 'Nu mai sunt bilete disponibile pentru acest tip.'}, status=400)

            # determinăm următorul număr din intervalul tipului
            if tip.ultimul_nr_alocat and tip.ultimul_nr_alocat > 0:
                nou_numar_serie = tip.ultimul_nr_alocat + 1
            else:
                nou_numar_serie = tip.interval_start

            # actualizăm contorul
            tip.ultimul_nr_alocat = nou_numar_serie
            tip.nr_vandute += 1
            tip.save()

            bilet = Bilet.objects.create(
                tip_bilet=tip,
                nume_participant=nume,
                email_participant=email,
                nr_serie=nou_numar_serie
            )
            genereaza_pdf_bilet(bilet.id)
            # Trimitere email direct după creare
            trimite_email_bilet(id_bilet=bilet.id, subiect="Ai primit un bilet nou! - Biletis.RO", destinatar=bilet.email_participant)

    except TipBilet.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': 'Tipul de bilet nu există.'}, status=400)
    except Exception as e:
        # Loghează eroarea aici, dacă ai logger configurat
        print(e)
        return JsonResponse({'status': 'error', 'message': 'A apărut o eroare internă.'}, status=500)

    messages.success(request, "Biletul a fost adaugat cu succes!")
    return JsonResponse({'status': 'success', 'message': 'Bilet adăugat cu succes.'})



@login_required
def bilete_vandute(request, slug):
    event = get_object_or_404(Event, slug=slug, organizator=request.user)

    tipuri_bilete = event.tipuri_bilete.all()
    query = request.GET.get('q', '')

    bilete = Bilet.objects.select_related('tip_bilet').filter(tip_bilet__event=event)

    if query:
        bilete = bilete.filter(
            Q(nume_participant__icontains=query) |
            Q(email_participant__icontains=query) |
            Q(tip_bilet__nume__icontains=query)
        )

    bilete = bilete.order_by('-nr_serie')

    # --- aici setăm nr. de bilete pe pagină ---
    per_page = request.GET.get('per_page', 25)
    try:
        per_page = int(per_page)
    except ValueError:
        per_page = 25

    paginator = Paginator(bilete, per_page)
    page_number = request.GET.get('page')
    bilete_page = paginator.get_page(page_number)

    context = {
        'event': event,
        'tipuri_bilete': tipuri_bilete,
        'bilete': bilete_page,
        'query': query,
        'per_page': per_page,
    }
    return render(request, 'organizator/events/bilete_vandute.html', context)


#view editare bilet vandut

@login_required
def editeaza_bilet(request, id):
    bilet = get_object_or_404(Bilet, id=id)

    # Asigurare că userul este organizatorul acelui eveniment
    if bilet.tip_bilet.event.organizator != request.user:
        messages.error(request, "Nu ai permisiunea să editezi acest bilet.")
        return redirect('dashboard')

    if request.method == "POST":
        bilet.nume_participant = request.POST.get("nume_participant")
        bilet.email_participant = request.POST.get("email_participant")

        tip_bilet_id = request.POST.get("tip_bilet")
        folosit = request.POST.get("folosit") == "True"

        bilet.tip_bilet = get_object_or_404(TipBilet, pk=tip_bilet_id)
        bilet.folosit = folosit

        bilet.save()

        # Generare PDF după ce biletul există în DB
        genereaza_pdf_bilet(bilet.id)
        messages.success(request, "Biletul a fost actualizat cu succes.")
        return redirect('bilete_vandute', slug=bilet.tip_bilet.event.slug)
    
#view stergere bilet vandut

@login_required
@require_POST
def sterge_bilet(request, id):
    try:
        with transaction.atomic():
            bilet = Bilet.objects.select_related('tip_bilet').select_for_update().get(id=id)
            tip = bilet.tip_bilet

            if tip.nr_vandute > 0:
                tip.nr_vandute -= 1
                tip.save()

            bilet.delete()

        return JsonResponse({'status': 'success', 'message': 'Biletul a fost șters cu succes.'})
    
    except Bilet.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': 'Biletul nu a fost găsit.'}, status=404)

#view trimitere bilet

@login_required
@require_POST
def resend_email_bilet(request):

    bilet_id = request.POST.get("bilet_id")

    try:
        bilet = Bilet.objects.get(id=bilet_id, tip_bilet__event__organizator=request.user)
        trimite_email_bilet(id_bilet=bilet.id, subiect="[Retrimitere] Ai primit un bilet! - Biletis.ro", destinatar=bilet.email_participant)
        messages.success(request, "E-mailul a fost retrimis!")
        return JsonResponse({'status': 'success', 'message': 'E-mailul a fost retrimis.'})
    except Bilet.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': 'Biletul nu a fost găsit sau nu ai acces.'}, status=404)
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': 'Eroare internă la trimiterea emailului.'}, status=500)



#afisare bilet
def bilet_detail(request, id):
    bilet = get_object_or_404(Bilet.objects.select_related('tip_bilet__event__organizator'), id=id)

    # Generare QR code
    qr_data = bilet.get_qr_data()
    qr = qrcode.make(qr_data)
    buffer = BytesIO()
    qr.save(buffer, format="PNG")
    img_str = base64.b64encode(buffer.getvalue()).decode()

    context = {
        'bilet': bilet,
        'qr_base64': img_str,
    }
    return render(request, 'participant/bilet.html', context)


#view validare cod qr
@csrf_exempt
@login_required
def valideaza_bilet(request, slug):
    if request.method == 'POST':
        qr_data = request.POST.get('qr_data')
        if not qr_data or not qr_data.startswith('TICKNEX-BILET-'):
            return JsonResponse({'status': 'error', 'message': 'QR invalid.'})

        try:
            bilet_id = qr_data.split('TICKNEX-BILET-')[1]
            bilet = Bilet.objects.get(id=bilet_id)
            event = Event.objects.get(slug=slug)
        except (Bilet.DoesNotExist, Event.DoesNotExist):
            return JsonResponse({'status': 'error', 'message': 'Bilet inexistent.'})

        if bilet.tip_bilet.event != event:
            return JsonResponse({'status': 'error', 'message': 'Biletul nu aparține acestui eveniment.'})

        if bilet.folosit:
            return JsonResponse({'status': 'error', 'message': 'Biletul a fost deja folosit.'})

        bilet.folosit = True
        bilet.save()
        return JsonResponse({'status': 'success', 'message': 'Bilet valid. Acces permis.',
                             'nume' : bilet.nume_participant,
                              'tip' : str(bilet.tip_bilet),
                                })
    
    return JsonResponse({'status': 'error', 'message': 'Cerere invalidă.'})

#view scanare cod qr
@login_required
def scanare_bilet(request, slug):
    event = get_object_or_404(Event, slug=slug)

    # verificăm ca userul să fie organizatorul
    if request.user != event.organizator:
        return redirect('acces_interzis')

    return render(request, 'organizator/events/scanare_bilet.html', {'event': event})

#view stats event
@login_required
def statistici(request, slug):
    event = get_object_or_404(Event, slug=slug)

    # verificăm ca userul să fie organizatorul
    if request.user != event.organizator:
        return redirect('/')
    
    # Bilete vândute
    bilete = Bilet.objects.filter(tip_bilet__event=event)

    #nr total bilete
    nr_bilete = bilete.count()

    #nr bilete folosite
    nr_bilete_folosite = bilete.filter(folosit=True).count()


    # Comenzi
    nr_comenzi = Comanda.objects.filter(eveniment=event, achitata=True).count()

    # Încasări = sumă (nr_vandute * pret)
    incasari = TipBilet.objects.filter(event=event).aggregate(
        total=Sum(
            ExpressionWrapper(
                F("nr_vandute") * F("pret"),
                output_field=DecimalField(max_digits=12, decimal_places=2)
            )
        )
    )["total"] or 0

    # Formatăm cu 2 zecimale
    incasari = round(incasari, 2)

    context = {
        "event": event,
        "nr_bilete": nr_bilete,
        "nr_bilete_folosite": nr_bilete_folosite,
        "nr_comenzi": nr_comenzi,
        "incasari": incasari,
    }

    return render(request, "organizator/events/statistici.html", context)

#statice
def politica(request):
    return render(request, 'legal/politica.html')

def termenii(request):
    return render(request, 'legal/termeni.html')

def contact(request):
    return render(request, 'legal/contact.html')



def checkout_view(request, slug):
    event = get_object_or_404(Event, slug=slug)
    tipuri_bilete = TipBilet.objects.filter(event=event)

    # Pas: eliberăm biletele rezervate care au expirat
    expirare_comenzi_rezervate(event=event)

    # POST inițial - salvare selecții în sesiune
    if request.method == "POST" and not request.POST.get("selectie_finala"):
        selectii = {}
        for tip in tipuri_bilete:
            valoare = request.POST.get(f"bilete_{tip.id}")
            if valoare and valoare != "":
                try:
                    cantitate = int(valoare)
                    if cantitate > 0:
                        selectii[str(tip.id)] = cantitate
                except ValueError:
                    continue

        if not selectii:
            return redirect("eveniment_prezentare", slug=slug)

        request.session['selectii_bilete'] = selectii
        request.session['total'] = request.POST.get('total_mare')
        request.session['total_initial'] = request.POST.get('total_initial')
        request.session['taxa'] = request.POST.get('taxa_stripe')
        request.session['taxa_biletis'] = request.POST.get('taxa_biletis')
        return redirect("checkout", slug=slug)

    # POST final - plasare comanda
    if request.method == "POST" and request.POST.get("selectie_finala"):
        selectii = request.session.get('selectii_bilete', {})
        tip_ids = [int(tid) for tid in selectii.keys()]
        tipuri_bilete = TipBilet.objects.filter(id__in=tip_ids)

        # Pas 1: verificare sold out
        for tip in tipuri_bilete:
            cant_comandata = selectii.get(str(tip.id), 0)
            if tip.nr_vandute + cant_comandata > tip.nr_maxim:
                messages.error(request, f"Ne pare rău! Între timp, anumite tipuri de bilete s-au vândut!")
                return redirect("checkout", slug=slug)

        # Pas 2: rezervare bilete (increment nr_vandute)
        for tip in tipuri_bilete:
            cant_comandata = selectii.get(str(tip.id), 0)
            tip.nr_vandute += cant_comandata
            tip.save()

        #Pas 3: calcul taxe si totaluri
        
        def round2(x):
            return x.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
        
        total_initial = Decimal("0.00")

        for tip in tipuri_bilete:
            cant = selectii.get(str(tip.id), 0)
            total_initial += Decimal(str(tip.pret)) * cant

        total_initial = round2(total_initial)

        taxa_organizator = event.organizator.taxa_organizator
        procent_taxa = Decimal(str(event.organizator.procent_taxa))

        if not taxa_organizator:
            backend_total = total_initial
            backend_taxa_stripe = Decimal("0.00")
            backend_taxa_biletis = Decimal("0.00")
            backend_taxa_platforma = Decimal("0.00")
            backend_net = total_initial
        else:
            # estimare inițială
            total_mare = (total_initial + Decimal("1.00")) / (
                Decimal("1.00") - Decimal("0.015") - (procent_taxa / Decimal("100"))
            )

            EPSILON = Decimal("0.001")

            while True:
                taxa_stripe = round2(total_mare * Decimal("0.015") + Decimal("1.00"))
                taxa_biletis = round2(total_mare * (procent_taxa / Decimal("100")))
                net = round2(total_mare - taxa_stripe - taxa_biletis)

                if abs(net - total_initial) < EPSILON:
                    backend_total = round2(total_mare)
                    backend_taxa_stripe = taxa_stripe
                    backend_taxa_biletis = taxa_biletis
                    backend_net = net
                    break

                total_mare += Decimal("0.01")


        # Pas 4: generăm lista de bilete
        bilete_data = []
        total_bilete = sum(selectii.values())
        for i in range(total_bilete):
            tip_id_raw = request.POST.get(f"tip_bilet_id_{i}")
            nume = request.POST.get(f"nume_bilet_{i}")
            email = request.POST.get(f"email_bilet_{i}")
            if not tip_id_raw or not nume or not email:
                continue
            try:
                tip_id = int(tip_id_raw)
            except ValueError:
                continue
            bilete_data.append({"tip_id": tip_id, "nume": nume, "email": email})



        # Pas 5: creăm comanda cu rezervare 15 minute
        comanda = Comanda.objects.create(
            eveniment=event,
            nume=request.POST.get("nume"),
            email=request.POST.get("email"),
            telefon=request.POST.get("telefon"),
            adresa=request.POST.get("adresa"),
            bilete=bilete_data,
            total=backend_total,
            fee_biletis = backend_taxa_biletis,
            fee_stripe = backend_taxa_stripe,
            fee_total = backend_taxa_stripe + backend_taxa_biletis,
            plata_neta=backend_net,
            achitata=False,
        )

        # Setăm rezervarea expirabilă
        comanda.rezervata_pana = timezone.now() + timedelta(minutes=15)
        comanda.status = 'rezervata'
        comanda.save()

        trimite_email_plasare_comanda(
            id_comanda=comanda.id,
            subiect="Ai plasat o comandă! - Biletis.ro",
            destinatar=comanda.email
        )

        request.session.pop('selectii_bilete', None)
        return redirect(reverse("comanda_finalizata", kwargs={"comanda_id": comanda.id}))

    # GET normal
    selectii = request.session.get('selectii_bilete')
    if not selectii:
        return redirect("eveniment_prezentare", slug=slug)

    bilete_plate = []
    for tip_id_str, cant in selectii.items():
        tip = tipuri_bilete.get(id=int(tip_id_str))
        for _ in range(cant):
            bilete_plate.append(tip)

    total = request.session.get('total')
    total_initial = request.session.get('total_initial')
    taxa = request.session.get('taxa')
    taxa_biletis = request.session.get('taxa_biletis')

    context = {
        "event": event,
        "bilete_plate": bilete_plate,
        "total_comanda": total,
        "total_initial": total_initial,
        "taxa_biletis": taxa_biletis,
        "taxa": taxa
    }

    if request.user.is_authenticated:
        context["user"] = request.user

    return render(request, "achizitie/checkout.html", context)


def comanda_finalizata(request, comanda_id):
    comanda = Comanda.objects.get(id=comanda_id)
    expirare_comenzi_rezervate(event=comanda.eveniment)

    

    context = {
        'event':comanda.eveniment,
        'comanda': comanda,
        'STRIPE_PUBLISHABLE_KEY': settings.STRIPE_PUBLISHABLE_KEY,
        'stripe_account_id':comanda.eveniment.organizator.stripe_account_id
    }
    return render(request, 'achizitie/comanda_finalizata.html', context)

#view-uri conectare organizator stripe

@login_required
def configurari_dashboard(request):
    user = request.user

    if request.method == "POST":
        user.companie_nume = request.POST.get("nume_companie", "")
        user.companie_adresa = request.POST.get("adresa", "")
        user.companie_cod_fiscal = request.POST.get("cod_fiscal", "")
        user.companie_cont_bancar = request.POST.get("cont_bancar", "")
        user.companie_email = request.POST.get("email_facturare", "")
        user.companie_telefon = request.POST.get("telefon_facturare", "")

        user.platitor_tva = True if request.POST.get("platitor_tva") == "on" else False
        user.cota_tva = request.POST.get("cota_tva", "0")

        user.save()
        messages.success(request, "Informațiile despre companie au fost salvate.")
        return redirect("configurari")

    return render(request, 'organizator/configurari.html', {"user": user})


@login_required
def connect_stripe(request):
    user = request.user
    if not user.stripe_account_id:
        # Creare cont Stripe Connect cu capabilități cerute
        account = stripe.Account.create(
            type='express',
            country='RO',
            email=user.email,
            capabilities={
                'card_payments': {'requested': True},
                'transfers': {'requested': True},
            },
        )
        user.stripe_account_id = account.id
        user.save()
    else:
        account = stripe.Account.retrieve(user.stripe_account_id)

    # Creare link onboarding
    account_link = stripe.AccountLink.create(
        account=account.id,
        refresh_url=request.build_absolute_uri(reverse('connect_stripe')),
        return_url=request.build_absolute_uri(reverse('verifica_capabilitati')),
        type='account_onboarding',
    )
    return redirect(account_link.url)

@login_required
def verifica_capabilitati(request):
    user = request.user
    if not user.stripe_account_id:
        return redirect('connect_stripe')

    account = stripe.Account.retrieve(user.stripe_account_id)

    # Obținem statusul capabilităților
    capabilities = account.get('capabilities', {})

    # Pentru afișare în template, putem prelucra datele
    context = {
        'account_id': user.stripe_account_id,
        'capabilities': capabilities,
    }
    return render(request, 'organizator/verifica_capabilitati.html', context)



@login_required
def stripe_callback(request):
    messages.success(request, "Contul Stripe a fost conectat cu succes!")
    return redirect('configurari')

@require_POST
def creeaza_sesiune_stripe(request, comanda_id):
    comanda = get_object_or_404(Comanda, id=comanda_id)
    print("se apeleaza")

    # Verificare cont Stripe conectat la organizator
    organizator = comanda.eveniment.organizator
    stripe_account_id = organizator.stripe_account_id

    if not stripe_account_id:
        return JsonResponse({'error': 'Organizatorul nu are un cont Stripe conectat.'}, status=400)

    # Verifică suma totală
    if comanda.total <= 0:
        return JsonResponse({'error': 'Valoarea totală a comenzii este invalidă.'}, status=400)

    try:
        print("incearca")
        # Creează sesiunea de plată Stripe (Stripe Connect)
        session = stripe.checkout.Session.create(
            payment_method_types=['card'],
            line_items=[{
                'price_data': {
                    'currency': 'ron',  # poți folosi și 'eur' dacă e mai stabil
                    'product_data': {
                        'name': f'Comandă #{comanda.nr_serie}',
                    },
                    'unit_amount': int(comanda.total * 100),  # totalul în bani (cenți)
                },
                'quantity': 1,
            }],
            mode='payment',
            success_url=request.build_absolute_uri(reverse('confirmare_plata', args=[comanda.id])),
            cancel_url=request.build_absolute_uri(reverse('comanda_finalizata', args=[comanda.id])),
            payment_intent_data={
                # Poți modifica comisionul dacă vrei să iei un fee
                # Dacă nu vrei fee, comentează linia de mai jos
                'application_fee_amount': int(comanda.fee_biletis * 100),
            },
            stripe_account=stripe_account_id,  # plata merge în contul organizatorului
        )
    
        #salvare session
        comanda.checkout_session_id = session.id
        comanda.save()

        return JsonResponse({'id': session.id})
    
    except Exception as e:
        print("EROARE STRIPE:", str(e))
        return JsonResponse({'error': 'A apărut o eroare la crearea sesiunii Stripe.'}, status=400)

@require_GET
def confirmare_plata(request, comanda_id):
    comanda = get_object_or_404(Comanda, id=comanda_id)

    stripe.api_key = settings.STRIPE_SECRET_KEY


    try:
        sesiune = stripe.checkout.Session.retrieve(
            comanda.checkout_session_id,
            stripe_account=comanda.eveniment.organizator.stripe_account_id
        )

        if sesiune.payment_status != 'paid':
            return HttpResponse("Plata nu a fost confirmată de Stripe.", status=400)
        

        comanda.platita = True
        comanda.save()

    except Exception as e:
        print("Stripe retrieve error:", str(e))
        return HttpResponse("Sesiunea Stripe nu a fost găsită. Plata nu poate fi confirmată.", status=400)

    # Dacă comanda nu e deja marcată ca achitată, procesăm
    if not comanda.achitata:
        with transaction.atomic():
            comanda.achitata = True
            comanda.status = 'achitata'
            comanda.save()

            """
            #creare chitanta pt comanda
            Chitanta.objects.create(comanda=comanda)
            """

            #trimitere mail comanda achitata
            trimite_email_comanda( comanda=comanda,
                                subiect="Comandă finalizată - Biletis.ro",
                                destinatar=comanda.email)

            for bilet_data in comanda.bilete:
                tip_id = bilet_data.get("tip_id")
                nume_participant = bilet_data.get("nume")
                email_participant = bilet_data.get("email")

                tip = TipBilet.objects.select_for_update().get(
                    id=tip_id,
                    event=comanda.eveniment
                )

                if tip.ultimul_nr_alocat and tip.ultimul_nr_alocat > 0:
                    nr_serie_nou = tip.ultimul_nr_alocat + 1
                else:
                    nr_serie_nou = tip.interval_start

                tip.ultimul_nr_alocat = nr_serie_nou
                tip.save()

                bilet = Bilet.objects.create(
                    tip_bilet=tip,
                    nume_participant=nume_participant,
                    email_participant=email_participant,
                    nr_serie=nr_serie_nou
                )
                genereaza_pdf_bilet(bilet.id)
                trimite_email_bilet(id_bilet=bilet.id,
                                    subiect="Ai primit un bilet nou! - Biletis.ro",
                                    destinatar=bilet.email_participant)

    return render(request, 'achizitie/confirmare.html', {'comanda': comanda})


#view afisare comenzi
@login_required
def comenzi_user(request):
    comenzi = Comanda.objects.filter(eveniment__organizator=request.user).order_by('-nr_serie')[:25]



    if request.method == 'POST':
        nr_input = request.POST.get('nr_comanda', '').strip()
        nr_pad = nr_input.zfill(6)  # transformă 39 → 000039

        try:
            comanda = Comanda.objects.get(
                nr_serie=nr_pad,
                eveniment__organizator=request.user
            )
            return redirect('detalii_comanda', comanda_id=comanda.id)
        except Comanda.DoesNotExist:
            messages.error(request, f"Comanda {nr_input} nu există sau nu îți aparține.")


    return render(request, 'organizator/comenzile_mele.html', {'comenzi': comenzi})

#view afisare comanda
@login_required
def detalii_comanda(request, comanda_id):
    comanda = get_object_or_404(Comanda, id=comanda_id, eveniment__organizator=request.user)

    # Procesăm biletele pentru a adăuga numele tipului de bilet
    bilete_cu_tip = []
    for b in comanda.bilete:
        try:
            tip = TipBilet.objects.get(id=b["tip_id"])
            b["tip_nume"] = tip.nume
        except TipBilet.DoesNotExist:
            b["tip_nume"] = "Necunoscut"
        bilete_cu_tip.append(b)

    context = {
        'comanda': comanda,
        'bilete': bilete_cu_tip,
    }
    return render(request, 'organizator/comanda.html', context)


@login_required
def raport_fiscal(request):
    organizator = request.user

    luni_ro = {
        1: "Ianuarie", 2: "Februarie", 3: "Martie", 4: "Aprilie",
        5: "Mai", 6: "Iunie", 7: "Iulie", 8: "August",
        9: "Septembrie", 10: "Octombrie", 11: "Noiembrie", 12: "Decembrie",
    }

    # toate evenimentele cu data setată
    evenimente = Event.objects.filter(
        organizator=organizator,
        data__isnull=False
    )

    ani = sorted({ev.data.year for ev in evenimente})

    # ==========================
    # AJAX: luni disponibile după an
    # ==========================
    if request.GET.get("actiune") == "get_luni":
        try:
            an = int(request.GET.get("an"))
        except (TypeError, ValueError):
            return JsonResponse({"luni": []})

        evs = Event.objects.filter(
            organizator=organizator,
            data__year=an,
            data__isnull=False
        )

        luni_disponibile = sorted({ev.data.month for ev in evs})
        luni_formatate = [{"numar": m, "nume": luni_ro[m]} for m in luni_disponibile]

        return JsonResponse({"luni": luni_formatate})

    # ==========================
    # AJAX: generare raport lunar per eveniment
    # ==========================
    if request.GET.get("actiune") == "genereaza_raport_lunar":
        try:
            an = int(request.GET.get("an"))
            luna = int(request.GET.get("luna"))
        except (TypeError, ValueError):
            return JsonResponse({"evenimente": []})

        # filtrare sigură cu interval de date (timezone-safe)
        start_date = datetime(an, luna, 1)
        if luna == 12:
            end_date = datetime(an + 1, 1, 1)
        else:
            end_date = datetime(an, luna + 1, 1)

        evs = Event.objects.filter(
            organizator=organizator,
            data__gte=start_date,
            data__lt=end_date
        )

        rezultat = []
        for ev in evs:
            tipuri = TipBilet.objects.filter(event=ev)
            comenzi = Comanda.objects.filter(eveniment=ev).count()

            raport = []
            total_bilete = 0
            total_incasari = Decimal("0.00")

            for idx, tb in enumerate(tipuri, start=1):
                vandute = tb.nr_vandute or 0
                pret = (tb.pret or Decimal("0.00")).quantize(Decimal("0.00"))
                total = (pret * vandute).quantize(Decimal("0.00"))

                total_bilete += vandute
                total_incasari += total

                raport.append({
                    "nr": idx,
                    "tip_bilet": tb.nume,
                    "vandute": vandute,
                    "pret_unitar": f"{pret:.2f}",
                    "total": f"{total:.2f}",
                })

            rezultat.append({
                "event_id": ev.id,
                "nume": ev.nume,
                "raport": raport,
                "total_bilete": total_bilete,
                "total_incasari": f"{total_incasari:.2f}",
                "nr_comenzi": comenzi,
            })

        return JsonResponse({"evenimente": rezultat})

    # ==========================
    # Render pagină
    # ==========================
    return render(request, "organizator/raport_fiscal.html", {
        "ani": ani,
    })


@login_required
def documente(request):
    if request.user.role != "organizator":
        raise PermissionError("Nu ai acces la această pagină.")

    files_qs = UserFile.objects.filter(user=request.user).order_by('folder', 'uploaded_at')

    # dict: folder -> lista de fisiere cu nume + url
    folder_files = {}
    for f in files_qs:
        folder_files.setdefault(f.folder, []).append({
            'name': os.path.basename(f.file.name),  # nume simplu
            'url': f.file.url
        })

    return render(request, 'organizator/documente.html', {
        'folder_files': folder_files
    })
"""
def chitanta(request, comanda_id):
    # Obține comanda sau returnează 404 dacă nu există
    comanda = get_object_or_404(Comanda, id=comanda_id)

    # Obține chitanta asociată sau returnează 404 dacă nu există
    chitanta = get_object_or_404(Chitanta, comanda=comanda)

    context = {
        'comanda': comanda,
        'chitanta': chitanta
    }

    return render(request, 'chitanta.html', context)
"""
