#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script pentru verificarea aleatorității șirurilor binare
Implementează multiple teste statistice pentru a determina dacă un șir binar este cu adevărat aleator
"""

import math
import numpy as np
from scipy import stats, special
from collections import Counter
import os
import sys

class TestAleatoritate:
    """Clasă pentru testarea aleatorității șirurilor binare"""
    
    def __init__(self, sir_binar):
        """
        Inițializează testul cu șirul binar
        
        Args:
            sir_binar: String format din 0 și 1
        """
        # Curăță șirul de caractere nedorite
        self.sir_original = sir_binar
        self.sir = ''.join(c for c in sir_binar if c in '01')
        self.n = len(self.sir)
        self.bits = [int(b) for b in self.sir]
        
        # Praguri de semnificație statistică
        self.alpha = 0.01  # Nivel de semnificație 1%
        
        print(f"\n{'='*80}")
        print(f"ANALIZA ALEATORITĂȚII ȘIRULUI BINAR")
        print(f"{'='*80}")
        print(f"Lungime șir: {self.n} biți")
        print(f"Număr de 0: {self.sir.count('0')}")
        print(f"Număr de 1: {self.sir.count('1')}")
        print(f"{'='*80}\n")
    
    def test_frecventa_monobit(self):
        """
        Test de frecvență (monobit) - NIST SP 800-22
        Verifică dacă numărul de 0 și 1 este aproximativ egal
        """
        print("1. TEST FRECVENȚĂ (MONOBIT)")
        print("-" * 40)
        
        # Calculează suma biților (tratând 0 ca -1)
        s = sum([2*b - 1 for b in self.bits])
        
        # Statistică de test
        s_obs = abs(s) / math.sqrt(self.n)
        
        # P-value folosind funcția de eroare complementară
        p_value = special.erfc(s_obs / math.sqrt(2))
        
        print(f"   Suma ajustată S: {s}")
        print(f"   Statistică test: {s_obs:.6f}")
        print(f"   P-value: {p_value:.6f}")
        
        rezultat = p_value >= self.alpha
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Distribuție echilibrată de biți' if rezultat else 'Distribuție dezechilibrată - posibil ne-aleator'}")
        print()
        
        return rezultat, p_value
    
    def test_frecventa_bloc(self, m=8):
        """
        Test de frecvență pe blocuri - NIST SP 800-22
        Verifică distribuția de pattern-uri în blocuri de m biți
        """
        print(f"2. TEST FRECVENȚĂ PE BLOCURI (M={m})")
        print("-" * 40)
        
        # Numărul de blocuri
        n_blocks = self.n // m
        
        if n_blocks < 1:
            print("   Șir prea scurt pentru acest test")
            return None, None
        
        # Calculează proporția de 1 în fiecare bloc
        proportii = []
        for i in range(n_blocks):
            bloc = self.bits[i*m:(i+1)*m]
            proportii.append(sum(bloc) / m)
        
        # Calculează statistica chi-pătrat
        chi_squared = 4 * m * sum([(pi - 0.5)**2 for pi in proportii])
        
        # P-value
        p_value = 1 - stats.chi2.cdf(chi_squared, n_blocks)
        
        print(f"   Număr blocuri: {n_blocks}")
        print(f"   Chi-pătrat: {chi_squared:.6f}")
        print(f"   P-value: {p_value:.6f}")
        
        rezultat = p_value >= self.alpha
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Frecvențe uniforme în blocuri' if rezultat else 'Distribuție neuniformă în blocuri'}")
        print()
        
        return rezultat, p_value
    
    def test_runs(self):
        """
        Test Runs - NIST SP 800-22
        Verifică oscilația între 0 și 1 (numărul de secvențe continue)
        """
        print("3. TEST RUNS (SECVENȚE CONTINUE)")
        print("-" * 40)
        
        # Pre-test: verifică proporția de 1
        pi = sum(self.bits) / self.n
        tau = 2 / math.sqrt(self.n)
        
        if abs(pi - 0.5) >= tau:
            print(f"   Pre-test eșuat: proporție de 1 = {pi:.6f}")
            print(f"   Șirul nu trece pre-testul pentru Runs")
            return False, 0
        
        # Calculează numărul de runs
        runs = 1
        for i in range(1, self.n):
            if self.bits[i] != self.bits[i-1]:
                runs += 1
        
        # Valoare așteptată și p-value
        runs_expected = 2 * self.n * pi * (1 - pi) + 1
        variance = 2 * pi * (1 - pi) * (2 * pi * (1 - pi) - 1)
        
        if variance > 0:
            z = (runs - runs_expected) / (math.sqrt(2 * self.n) * math.sqrt(variance))
            p_value = special.erfc(abs(z) / math.sqrt(2))
        else:
            p_value = 0
        
        print(f"   Număr de runs observat: {runs}")
        print(f"   Număr de runs așteptat: {runs_expected:.2f}")
        print(f"   P-value: {p_value:.6f}")
        
        rezultat = p_value >= self.alpha
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Oscilație normală între 0 și 1' if rezultat else 'Oscilație anormală - posibile pattern-uri'}")
        print()
        
        return rezultat, p_value
    
    def test_longest_run(self):
        """
        Test Longest Run of Ones - NIST SP 800-22
        Verifică lungimea maximă a secvențelor de 1
        """
        print("4. TEST LONGEST RUN OF ONES")
        print("-" * 40)
        
        # Parametri în funcție de lungimea șirului
        if self.n < 128:
            print("   Șir prea scurt pentru acest test (minim 128 biți)")
            return None, None
        elif self.n < 6272:
            m = 8
            k = 3
            v_obs = [0, 0, 0, 0]
            pi = [0.2148, 0.3672, 0.2305, 0.1875]
        elif self.n < 750000:
            m = 128
            k = 5
            v_obs = [0, 0, 0, 0, 0, 0]
            pi = [0.1174, 0.2430, 0.2493, 0.1752, 0.1027, 0.1124]
        else:
            m = 10000
            k = 6
            v_obs = [0, 0, 0, 0, 0, 0, 0]
            pi = [0.0882, 0.2092, 0.2483, 0.1933, 0.1208, 0.0675, 0.0727]
        
        # Împarte în blocuri
        n_blocks = self.n // m
        
        # Pentru fiecare bloc, găsește longest run
        for bloc_idx in range(n_blocks):
            start = bloc_idx * m
            end = start + m
            bloc = self.sir[start:end]
            
            # Găsește longest run în bloc
            max_run = 0
            current_run = 0
            for bit in bloc:
                if bit == '1':
                    current_run += 1
                    max_run = max(max_run, current_run)
                else:
                    current_run = 0
            
            # Categorizează
            if self.n < 6272:
                if max_run <= 1:
                    v_obs[0] += 1
                elif max_run == 2:
                    v_obs[1] += 1
                elif max_run == 3:
                    v_obs[2] += 1
                else:
                    v_obs[3] += 1
            elif self.n < 750000:
                if max_run <= 4:
                    v_obs[0] += 1
                elif max_run == 5:
                    v_obs[1] += 1
                elif max_run == 6:
                    v_obs[2] += 1
                elif max_run == 7:
                    v_obs[3] += 1
                elif max_run == 8:
                    v_obs[4] += 1
                else:
                    v_obs[5] += 1
        
        # Calculează chi-pătrat
        chi_squared = sum([(v_obs[i] - n_blocks * pi[i])**2 / (n_blocks * pi[i]) for i in range(len(pi))])
        p_value = 1 - stats.chi2.cdf(chi_squared, k)
        
        print(f"   Mărime bloc: {m}")
        print(f"   Număr blocuri: {n_blocks}")
        print(f"   Chi-pătrat: {chi_squared:.6f}")
        print(f"   P-value: {p_value:.6f}")
        
        rezultat = p_value >= self.alpha
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Lungimi normale de secvențe' if rezultat else 'Secvențe anormal de lungi/scurte'}")
        print()
        
        return rezultat, p_value
    
    def test_entropia_shannon(self):
        """
        Test Entropie Shannon
        Măsoară cantitatea de informație/aleatoritate
        """
        print("5. TEST ENTROPIE SHANNON")
        print("-" * 40)
        
        # Calculează entropia pentru biți individuali
        p0 = self.sir.count('0') / self.n
        p1 = self.sir.count('1') / self.n
        
        if p0 > 0 and p1 > 0:
            H1 = -p0 * math.log2(p0) - p1 * math.log2(p1)
        else:
            H1 = 0
        
        # Calculează entropia pentru perechi de biți
        perechi = {}
        for i in range(self.n - 1):
            pereche = self.sir[i:i+2]
            perechi[pereche] = perechi.get(pereche, 0) + 1
        
        H2 = 0
        total_perechi = sum(perechi.values())
        for count in perechi.values():
            if count > 0:
                p = count / total_perechi
                H2 -= p * math.log2(p)
        
        # Entropie normalizată
        H2_norm = H2 / 2 if H2 > 0 else 0
        
        print(f"   Entropie biți (H1): {H1:.6f} / 1.0")
        print(f"   Entropie perechi normalizată: {H2_norm:.6f} / 1.0")
        print(f"   Grad de aleatoritate: {H1*100:.1f}%")
        
        rezultat = H1 > 0.95  # Pragul pentru aleatoritate bună
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Entropie înaltă - bună aleatoritate' if rezultat else 'Entropie scăzută - posibile pattern-uri'}")
        print()
        
        return rezultat, H1
    
    def test_chi_squared(self):
        """
        Test Chi-pătrat pentru uniformitate
        Verifică distribuția uniformă a pattern-urilor
        """
        print("6. TEST CHI-PĂTRAT PENTRU UNIFORMITATE")
        print("-" * 40)
        
        # Test pe octeți (8 biți)
        if self.n < 8:
            print("   Șir prea scurt pentru acest test")
            return None, None
        
        # Creează octeți
        octeti = []
        for i in range(0, self.n - 7, 8):
            octet = self.sir[i:i+8]
            octeti.append(octet)
        
        # Frecvențe observate
        frecvente = Counter(octeti)
        n_octeti = len(octeti)
        
        # Frecvență așteptată pentru distribuție uniformă
        expected = n_octeti / 256
        
        if expected < 5:
            print(f"   Prea puține date pentru test chi-pătrat robust")
            print(f"   (Se recomandă minim {256*5} biți)")
        
        # Calculează chi-pătrat
        chi_squared = 0
        for i in range(256):
            octet = format(i, '08b')
            observed = frecvente.get(octet, 0)
            if expected > 0:
                chi_squared += (observed - expected)**2 / expected
        
        # Grade de libertate și p-value
        df = min(255, len(frecvente) - 1)
        if df > 0:
            p_value = 1 - stats.chi2.cdf(chi_squared, df)
        else:
            p_value = 0
        
        print(f"   Număr octeți analizați: {n_octeti}")
        print(f"   Pattern-uri unice găsite: {len(frecvente)}/256")
        print(f"   Chi-pătrat: {chi_squared:.2f}")
        print(f"   P-value: {p_value:.6f}")
        
        rezultat = p_value >= self.alpha
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Distribuție uniformă' if rezultat else 'Distribuție neuniformă - pattern-uri repetitive'}")
        print()
        
        return rezultat, p_value
    
    def test_autocorrelatie(self, lag=1):
        """
        Test de autocorelare
        Verifică independența dintre biți la distanță 'lag'
        """
        print(f"7. TEST AUTOCORELARE (LAG={lag})")
        print("-" * 40)
        
        if self.n <= lag:
            print("   Șir prea scurt pentru acest lag")
            return None, None
        
        # Calculează autocorelare
        suma = 0
        for i in range(self.n - lag):
            suma += (self.bits[i] - 0.5) * (self.bits[i + lag] - 0.5)
        
        autocorr = suma / (self.n - lag)
        
        # Statistică de test sub ipoteza de independență
        z = autocorr * math.sqrt(self.n - lag) * 2
        p_value = 2 * (1 - stats.norm.cdf(abs(z)))
        
        print(f"   Coeficient autocorelare: {autocorr:.6f}")
        print(f"   Statistică Z: {z:.6f}")
        print(f"   P-value: {p_value:.6f}")
        
        rezultat = p_value >= self.alpha
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Biți independenți' if rezultat else 'Dependență detectată între biți'}")
        print()
        
        return rezultat, p_value
    
    def test_compresie(self):
        """
        Test de compresibilitate
        Verifică dacă șirul poate fi comprimat (date aleatoare nu pot fi comprimate)
        """
        print("8. TEST COMPRESIBILITATE")
        print("-" * 40)
        
        import zlib
        
        # Convertește șirul în bytes
        sir_bytes = bytes([int(self.sir[i:i+8], 2) for i in range(0, self.n-7, 8)])
        
        # Comprimă
        sir_comprimat = zlib.compress(sir_bytes, level=9)
        
        # Calculează rata de compresie
        lungime_originala = len(sir_bytes)
        lungime_comprimata = len(sir_comprimat)
        rata_compresie = lungime_comprimata / lungime_originala
        
        print(f"   Lungime originală: {lungime_originala} bytes")
        print(f"   Lungime comprimată: {lungime_comprimata} bytes")
        print(f"   Rata de compresie: {rata_compresie:.3f}")
        
        # Date cu adevărat aleatoare nu pot fi comprimate semnificativ
        rezultat = rata_compresie > 0.95  # Pragul pentru date aleatoare
        
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Incompresibil - bună aleatoritate' if rezultat else 'Compresibil - conține pattern-uri'}")
        print()
        
        return rezultat, rata_compresie
    
    def test_serial(self, m=2):
        """
        Test Serial - NIST SP 800-22
        Verifică uniformitatea tuturor posibilelor pattern-uri de m biți
        """
        print(f"9. TEST SERIAL (M={m})")
        print("-" * 40)
        
        if self.n < m:
            print("   Șir prea scurt pentru acest test")
            return None, None
        
        # Funcție pentru calcularea psi_m
        def psi_squared(m, bits_extended):
            patterns = {}
            for i in range(len(bits_extended) - m + 1):
                pattern = tuple(bits_extended[i:i+m])
                patterns[pattern] = patterns.get(pattern, 0) + 1
            
            psi = 0
            for count in patterns.values():
                psi += count**2
            psi = (2**m / self.n) * psi - self.n
            return psi
        
        # Extinde șirul circular
        bits_extended = self.bits + self.bits[:m-1]
        
        # Calculează psi pentru m, m-1, m-2
        psi_m = psi_squared(m, bits_extended)
        psi_m1 = psi_squared(m-1, bits_extended)
        psi_m2 = psi_squared(m-2, bits_extended) if m >= 2 else 0
        
        # Calculează statisticile
        delta_psi = psi_m - psi_m1
        delta2_psi = psi_m - 2*psi_m1 + psi_m2
        
        # P-values
        p_value1 = special.gammaincc(2**(m-2), delta_psi/2)
        p_value2 = special.gammaincc(2**(m-3), delta2_psi/2) if m >= 2 else 1
        
        print(f"   ΔΨ²m: {delta_psi:.6f}")
        print(f"   Δ²Ψ²m: {delta2_psi:.6f}")
        print(f"   P-value 1: {p_value1:.6f}")
        print(f"   P-value 2: {p_value2:.6f}")
        
        rezultat = p_value1 >= self.alpha and p_value2 >= self.alpha
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Pattern-uri uniform distribuite' if rezultat else 'Distribuție neuniformă de pattern-uri'}")
        print()
        
        return rezultat, min(p_value1, p_value2)
    
    def test_complexitate_liniar(self, M=500):
        """
        Test de Complexitate Liniară - NIST SP 800-22
        Verifică complexitatea liniară a secvențelor
        """
        print(f"10. TEST COMPLEXITATE LINIARĂ (M={M})")
        print("-" * 40)
        
        if self.n < M:
            print("   Șir prea scurt pentru acest test")
            return None, None
        
        # Numărul de blocuri
        N = self.n // M
        
        if N < 1:
            print("   Nu sunt suficiente blocuri pentru test")
            return None, None
        
        # Pentru fiecare bloc, calculează complexitatea liniară
        complexitati = []
        
        for bloc_idx in range(N):
            start = bloc_idx * M
            bloc = self.bits[start:start+M]
            
            # Algoritmul Berlekamp-Massey simplificat
            L = 0
            m_val = -1
            B = [0] * M
            C = [0] * M
            B[0] = 1
            C[0] = 1
            
            for n in range(M):
                d = bloc[n]
                for i in range(1, L+1):
                    if n-i >= 0:
                        d ^= C[i] & bloc[n-i]
                
                if d == 1:
                    T = C.copy()
                    for i in range(M):
                        if n - m_val + i < M and B[i] == 1:
                            C[n - m_val + i] ^= 1
                    
                    if L <= n // 2:
                        L = n + 1 - L
                        m_val = n
                        B = T
            
            complexitati.append(L)
        
        # Calculează statistică
        mu = M/2 + (9 + (-1)**(M+1))/36 - (M/3 + 2/9)/2**M
        
        # Număr de blocuri cu complexitate în diferite categorii
        v = [0] * 7
        for L in complexitati:
            if L <= mu - 2.5 * math.sqrt(mu):
                v[0] += 1
            elif L <= mu - 1.5 * math.sqrt(mu):
                v[1] += 1
            elif L <= mu - 0.5 * math.sqrt(mu):
                v[2] += 1
            elif L <= mu + 0.5 * math.sqrt(mu):
                v[3] += 1
            elif L <= mu + 1.5 * math.sqrt(mu):
                v[4] += 1
            elif L <= mu + 2.5 * math.sqrt(mu):
                v[5] += 1
            else:
                v[6] += 1
        
        # Probabilități teoretice
        pi = [0.010417, 0.03125, 0.125, 0.5, 0.25, 0.0625, 0.020833]
        
        # Chi-pătrat
        chi_squared = sum([(v[i] - N * pi[i])**2 / (N * pi[i]) for i in range(7) if N * pi[i] > 0])
        p_value = 1 - stats.chi2.cdf(chi_squared, 6)
        
        print(f"   Număr blocuri: {N}")
        print(f"   Complexitate medie așteptată: {mu:.2f}")
        print(f"   Chi-pătrat: {chi_squared:.6f}")
        print(f"   P-value: {p_value:.6f}")
        
        rezultat = p_value >= self.alpha
        print(f"   Rezultat: {'✓ TRECUT' if rezultat else '✗ EȘUAT'}")
        print(f"   Interpretare: {'Complexitate adecvată' if rezultat else 'Complexitate inadecvată - posibil generator slab'}")
        print()
        
        return rezultat, p_value
    
    def rezumat_final(self, rezultate):
        """
        Afișează rezumatul final al testelor
        """
        print("\n" + "="*80)
        print("REZUMAT FINAL")
        print("="*80)
        
        teste_trecute = sum(1 for r in rezultate.values() if r[0] is True)
        teste_totale = sum(1 for r in rezultate.values() if r[0] is not None)
        
        print(f"\nTeste trecute: {teste_trecute}/{teste_totale}")
        print(f"Rata de succes: {teste_trecute/teste_totale*100:.1f}%")
        
        # Evaluare finală
        print("\n" + "-"*40)
        print("EVALUARE FINALĂ:")
        print("-"*40)
        
        if teste_totale == 0:
            print("⚠ Nu s-au putut rula testele - șir prea scurt")
        elif teste_trecute == teste_totale:
            print("✓✓✓ EXCELENT: Șirul prezintă caracteristici de aleatoritate foarte bune!")
            print("    Toate testele au fost trecute cu succes.")
        elif teste_trecute >= teste_totale * 0.8:
            print("✓✓ BUN: Șirul prezintă caracteristici de aleatoritate bune.")
            print("    Majoritatea testelor au fost trecute.")
        elif teste_trecute >= teste_totale * 0.5:
            print("✓ ACCEPTABIL: Șirul prezintă unele caracteristici de aleatoritate.")
            print("    Recomandare: Verificați sursa de generare.")
        else:
            print("✗ SLAB: Șirul NU prezintă caracteristici de aleatoritate adecvate!")
            print("    Atenție: Nu utilizați pentru scopuri criptografice!")
        
        # Detalii despre testele eșuate
        teste_esuate = [nume for nume, (rezultat, _) in rezultate.items() if rezultat is False]
        if teste_esuate:
            print("\nTeste eșuate:")
            for test in teste_esuate:
                print(f"  • {test}")
        
        print("\n" + "="*80)


def main():
    """Funcția principală"""
    print("\n" + "="*80)
    print(" VERIFICATOR DE ALEATORITATE PENTRU ȘIRURI BINARE")
    print(" Generator Quantum & Analiza Statistică Avansată")
    print("="*80)
    
    # Solicită numele fișierului
    nume_fisier = input("\nIntroduceți numele fișierului (Enter pentru 'datebinare.txt'): ").strip()
    if not nume_fisier:
        nume_fisier = "datebinare.txt"
    
    # Caută fișierul în folderul curent
    cale_fisier = os.path.join(os.path.dirname(os.path.abspath(__file__)), nume_fisier)
    
    # Verifică dacă fișierul există
    if not os.path.exists(cale_fisier):
        print(f"\n⚠ Eroare: Fișierul '{nume_fisier}' nu a fost găsit!")
        print(f"  Căutare în: {cale_fisier}")
        
        # Creează un fișier exemplu
        print(f"\n→ Creez un fișier exemplu '{nume_fisier}' cu date de test...")
        with open(cale_fisier, 'w') as f:
            # Generează un șir binar aleator pentru test
            import random
            sir_test = ''.join(random.choice('01') for _ in range(10000))
            f.write(sir_test)
        print(f"  Fișier creat cu {len(sir_test)} biți de test.")
        print("  Puteți înlocui conținutul cu propriile date binare.")
    
    # Citește fișierul
    try:
        with open(cale_fisier, 'r') as f:
            sir_binar = f.read().strip()
        
        # Verifică dacă șirul conține doar 0 și 1
        caractere_invalide = set(sir_binar) - {'0', '1', ' ', '\n', '\r', '\t'}
        if caractere_invalide:
            print(f"\n⚠ Atenție: S-au găsit caractere invalide: {caractere_invalide}")
            print("  Acestea vor fi ignorate în analiză.")
        
        # Curăță șirul
        sir_curat = ''.join(c for c in sir_binar if c in '01')
        
        if len(sir_curat) == 0:
            print("\n✗ Eroare: Fișierul nu conține date binare valide (0 și 1)!")
            sys.exit(1)
        
        print(f"\n✓ Fișier încărcat cu succes!")
        print(f"  Total biți valizi: {len(sir_curat)}")
        
        # Rulează testele
        tester = TestAleatoritate(sir_curat)
        
        rezultate = {}
        
        # 1. Test Frecvență Monobit
        rezultate['Frecvență Monobit'] = tester.test_frecventa_monobit()
        
        # 2. Test Frecvență Bloc
        rezultate['Frecvență Bloc'] = tester.test_frecventa_bloc()
        
        # 3. Test Runs
        rezultate['Runs'] = tester.test_runs()
        
        # 4. Test Longest Run
        rezultate['Longest Run'] = tester.test_longest_run()
        
        # 5. Test Entropie Shannon
        rezultate['Entropie Shannon'] = tester.test_entropia_shannon()
        
        # 6. Test Chi-pătrat
        rezultate['Chi-pătrat'] = tester.test_chi_squared()
        
        # 7. Test Autocorelare
        rezultate['Autocorelare'] = tester.test_autocorrelatie()
        
        # 8. Test Compresibilitate
        rezultate['Compresibilitate'] = tester.test_compresie()
        
        # 9. Test Serial
        rezultate['Serial'] = tester.test_serial()
        
        # 10. Test Complexitate Liniară
        if len(sir_curat) >= 500:
            rezultate['Complexitate Liniară'] = tester.test_complexitate_liniar()
        
        # Afișează rezumatul
        tester.rezumat_final(rezultate)
        
        # Salvează raportul
        raport_nume = nume_fisier.rsplit('.', 1)[0] + '_raport.txt'
        print(f"\n💾 Salvare raport în: {raport_nume}")
        
        with open(os.path.join(os.path.dirname(cale_fisier), raport_nume), 'w', encoding='utf-8') as f:
            f.write("RAPORT DE ANALIZĂ ALEATORITATE\n")
            f.write("="*60 + "\n\n")
            f.write(f"Fișier analizat: {nume_fisier}\n")
            f.write(f"Lungime șir: {len(sir_curat)} biți\n")
            f.write(f"Data analizei: {os.popen('date').read().strip()}\n\n")
            f.write("REZULTATE TESTE:\n")
            f.write("-"*40 + "\n")
            
            for nume_test, (rezultat, p_value) in rezultate.items():
                if rezultat is not None:
                    status = "TRECUT" if rezultat else "EȘUAT"
                    f.write(f"{nume_test}: {status}")
                    if isinstance(p_value, float):
                        f.write(f" (p-value: {p_value:.6f})")
                    f.write("\n")
            
            teste_trecute = sum(1 for r in rezultate.values() if r[0] is True)
            teste_totale = sum(1 for r in rezultate.values() if r[0] is not None)
            f.write(f"\nREZUMAT: {teste_trecute}/{teste_totale} teste trecute\n")
            f.write(f"Rata succes: {teste_trecute/teste_totale*100:.1f}%\n")
        
        print("✓ Raport salvat cu succes!")
        
    except Exception as e:
        print(f"\n✗ Eroare la procesare: {str(e)}")
        import traceback
        traceback.print_exc()
        sys.exit(1)


if __name__ == "__main__":
    main()
