#!/usr/bin/env python3
"""
ENIGMA Inventario - Script di Diagnostica Completo
===================================================

Questo script verifica lo stato di tutti i componenti del sistema:
- Database connectivity e struttura
- Blueprint registration
- Endpoints availability
- Authentication flow
- API esterne
- Configurazione ambiente

Uso: python diagnostics.py [--verbose] [--fix-demo-user]
"""

import sys
import os
import requests
import pymysql
import bcrypt
from datetime import datetime
from colorama import init, Fore, Style
import json

# Inizializza colorama per output colorato
init(autoreset=True)

# Configurazione (da caricare da .env in produzione)
DB_CONFIG = {
    'host': 'localhost',
    'user': 'enigma_user',
    'password': 'arcana2026',
    'database': 'enigma',
    'charset': 'utf8mb4'
}

BASE_URL = 'http://localhost:5000'
DEMO_USER = {
    'email': 'demo@studium.it',
    'password': 'demo123',
    'tenant_code': 'DEMO'
}

class DiagnosticTester:
    def __init__(self, verbose=False):
        self.verbose = verbose
        self.results = {
            'passed': 0,
            'failed': 0,
            'warnings': 0
        }
        self.db_connection = None
        
    def print_header(self, text):
        """Stampa un header formattato"""
        print(f"\n{Fore.CYAN}{'=' * 70}")
        print(f"{Fore.CYAN}{text.center(70)}")
        print(f"{Fore.CYAN}{'=' * 70}{Style.RESET_ALL}\n")
    
    def print_test(self, name, status, message="", details=""):
        """Stampa il risultato di un test"""
        if status == "PASS":
            icon = f"{Fore.GREEN}✓"
            self.results['passed'] += 1
        elif status == "FAIL":
            icon = f"{Fore.RED}✗"
            self.results['failed'] += 1
        elif status == "WARN":
            icon = f"{Fore.YELLOW}⚠"
            self.results['warnings'] += 1
        else:
            icon = f"{Fore.BLUE}ℹ"
        
        print(f"{icon} {name}: {Style.RESET_ALL}{message}")
        if details and self.verbose:
            print(f"  {Fore.BLUE}└─ {details}{Style.RESET_ALL}")
    
    def test_database_connection(self):
        """Test 1: Verifica connessione al database"""
        self.print_header("TEST 1: DATABASE CONNECTION")
        
        try:
            self.db_connection = pymysql.connect(**DB_CONFIG)
            self.print_test(
                "Database Connection",
                "PASS",
                "Connessione al database riuscita",
                f"Host: {DB_CONFIG['host']}, DB: {DB_CONFIG['database']}"
            )
            return True
        except Exception as e:
            self.print_test(
                "Database Connection",
                "FAIL",
                f"Impossibile connettersi al database",
                str(e)
            )
            return False
    
    def test_database_structure(self):
        """Test 2: Verifica struttura tabelle"""
        self.print_header("TEST 2: DATABASE STRUCTURE")
        
        if not self.db_connection:
            self.print_test("Database Structure", "FAIL", "Nessuna connessione DB")
            return False
        
        required_tables = [
            'tenants',
            'tenant_users',
            'inv_sessioni_inventario',
            'inv_risultati_inventario',
            'inv_cache_prodotti',
            'inv_log_barcode',
            'inv_sedi',
            'audit_log'
        ]
        
        try:
            cursor = self.db_connection.cursor()
            cursor.execute("SHOW TABLES")
            existing_tables = [row[0] for row in cursor.fetchall()]
            
            all_present = True
            for table in required_tables:
                if table in existing_tables:
                    self.print_test(
                        f"Table: {table}",
                        "PASS",
                        "Tabella presente"
                    )
                else:
                    self.print_test(
                        f"Table: {table}",
                        "FAIL",
                        "Tabella mancante"
                    )
                    all_present = False
            
            return all_present
            
        except Exception as e:
            self.print_test(
                "Database Structure",
                "FAIL",
                "Errore nella verifica struttura",
                str(e)
            )
            return False
    
    def test_demo_user(self):
        """Test 3: Verifica utente demo"""
        self.print_header("TEST 3: DEMO USER VERIFICATION")
        
        if not self.db_connection:
            self.print_test("Demo User", "FAIL", "Nessuna connessione DB")
            return False
        
        try:
            cursor = self.db_connection.cursor(pymysql.cursors.DictCursor)
            
            # Verifica tenant
            cursor.execute(
                "SELECT * FROM tenants WHERE codice = %s",
                (DEMO_USER['tenant_code'],)
            )
            tenant = cursor.fetchone()
            
            if not tenant:
                self.print_test(
                    "Tenant DEMO",
                    "FAIL",
                    "Tenant non trovato"
                )
                return False
            
            self.print_test(
                "Tenant DEMO",
                "PASS",
                f"Tenant trovato (ID: {tenant['id']})"
            )
            
            # Verifica utente
            cursor.execute(
                """SELECT tu.*, t.codice as tenant_code
                   FROM tenant_users tu
                   JOIN tenants t ON tu.id_tenant = t.id
                   WHERE tu.email = %s AND t.codice = %s""",
                (DEMO_USER['email'], DEMO_USER['tenant_code'])
            )
            user = cursor.fetchone()
            
            if not user:
                self.print_test(
                    "User demo@studium.it",
                    "FAIL",
                    "Utente non trovato"
                )
                return False
            
            self.print_test(
                "User demo@studium.it",
                "PASS",
                f"Utente trovato (ID: {user['id']})"
            )
            
            # Verifica password hash
            if user['password_hash']:
                try:
                    # Test password verification
                    is_valid = bcrypt.checkpw(
                        DEMO_USER['password'].encode('utf-8'),
                        user['password_hash'].encode('utf-8')
                    )
                    
                    if is_valid:
                        self.print_test(
                            "Password Verification",
                            "PASS",
                            "Password hash valido"
                        )
                    else:
                        self.print_test(
                            "Password Verification",
                            "FAIL",
                            "Password hash non corrisponde"
                        )
                        return False
                        
                except Exception as e:
                    self.print_test(
                        "Password Verification",
                        "FAIL",
                        "Errore nella verifica password",
                        str(e)
                    )
                    return False
            else:
                self.print_test(
                    "Password Hash",
                    "FAIL",
                    "Password hash mancante"
                )
                return False
            
            return True
            
        except Exception as e:
            self.print_test(
                "Demo User",
                "FAIL",
                "Errore nella verifica utente",
                str(e)
            )
            return False
    
    def test_flask_endpoints(self):
        """Test 4: Verifica disponibilità endpoints"""
        self.print_header("TEST 4: FLASK ENDPOINTS")
        
        endpoints = [
            ('/', 'GET', 'Homepage'),
            ('/auth/login', 'GET', 'Login Page'),
            ('/auth/login', 'POST', 'Login API'),
            ('/health', 'GET', 'Health Check'),
        ]
        
        all_ok = True
        for endpoint, method, description in endpoints:
            url = f"{BASE_URL}{endpoint}"
            
            try:
                if method == 'GET':
                    response = requests.get(url, timeout=5, verify=True)
                else:
                    response = requests.post(
                        url,
                        json={},
                        timeout=5,
                        verify=True
                    )
                
                if response.status_code < 500:
                    self.print_test(
                        f"{method} {endpoint}",
                        "PASS",
                        f"{description} - Status: {response.status_code}"
                    )
                else:
                    self.print_test(
                        f"{method} {endpoint}",
                        "FAIL",
                        f"{description} - Server Error: {response.status_code}"
                    )
                    all_ok = False
                    
            except requests.exceptions.SSLError as e:
                self.print_test(
                    f"{method} {endpoint}",
                    "WARN",
                    f"{description} - SSL Error (potrebbe essere normale in dev)"
                )
            except Exception as e:
                self.print_test(
                    f"{method} {endpoint}",
                    "FAIL",
                    f"{description} - {str(e)}"
                )
                all_ok = False
        
        return all_ok
    
    def test_authentication_flow(self):
        """Test 5: Test completo flusso di autenticazione"""
        self.print_header("TEST 5: AUTHENTICATION FLOW")
        
        try:
            # Step 1: Login
            login_url = f"{BASE_URL}/auth/login"
            login_data = {
                'email': DEMO_USER['email'],
                'password': DEMO_USER['password'],
                'tenant_code': DEMO_USER['tenant_code']
            }
            
            self.print_test(
                "Login Request",
                "INFO",
                f"Tentativo login come {DEMO_USER['email']}"
            )
            
            response = requests.post(
                login_url,
                json=login_data,
                timeout=10,
                verify=True
            )
            
            if response.status_code == 200:
                data = response.json()
                # L'API può restituire "token" o "access_token"
                token = data.get('access_token') or data.get('token')
                
                if token:
                    self.print_test(
                        "Login Success",
                        "PASS",
                        "Token JWT ricevuto",
                        f"Token: {token[:20]}..."
                    )
                    
                    # Step 2: Test authenticated endpoint
                    headers = {'Authorization': f'Bearer {token}'}
                    
                    # Test inventory endpoint
                    inventory_url = f"{BASE_URL}/api/v1/inventory/sessions/recent"
                    inv_response = requests.get(
                        inventory_url,
                        headers=headers,
                        timeout=10,
                        verify=True
                    )
                    
                    if inv_response.status_code == 200:
                        self.print_test(
                            "Authenticated Request",
                            "PASS",
                            "Accesso al modulo inventory riuscito"
                        )
                        return True
                    else:
                        self.print_test(
                            "Authenticated Request",
                            "WARN",
                            f"Inventory endpoint: {inv_response.status_code} (potrebbe essere normale se import non fixato)",
                            inv_response.text[:200]
                        )
                        # Non fallire il test per questo
                        return True
                else:
                    self.print_test(
                        "Login Success",
                        "FAIL",
                        "Token non presente nella risposta",
                        json.dumps(data, indent=2)
                    )
                    return False
            else:
                self.print_test(
                    "Login Request",
                    "FAIL",
                    f"Login fallito - Status: {response.status_code}",
                    response.text[:200]
                )
                return False
                
        except Exception as e:
            self.print_test(
                "Authentication Flow",
                "FAIL",
                "Errore nel flusso di autenticazione",
                str(e)
            )
            return False
    
    def test_cassanova_api(self):
        """Test 6: Verifica connettività API Cassanova"""
        self.print_header("TEST 6: CASSANOVA API")
        
        # Carica configurazione API
        try:
            cursor = self.db_connection.cursor(pymysql.cursors.DictCursor)
            cursor.execute(
                "SELECT t.* FROM tenants t WHERE t.codice = %s",
                (DEMO_USER['tenant_code'],)
            )
            tenant = cursor.fetchone()
            
            if not tenant:
                self.print_test(
                    "API Key",
                    "FAIL",
                    "Tenant DEMO non trovato"
                )
                return False
            
            # Nota: il campo api_key potrebbe non esistere nello schema
            # Verifica se il campo esiste
            if 'api_key' not in tenant or not tenant.get('api_key'):
                self.print_test(
                    "API Key",
                    "WARN",
                    "Campo api_key non presente o vuoto nello schema tenants"
                )
                return False
            
            api_key = tenant['api_key']
            
            # Test connessione API
            api_url = "https://app.cassaincloud.it/api/v2/products"
            headers = {
                'Authorization': f'Bearer {api_key}',
                'Content-Type': 'application/json'
            }
            
            response = requests.get(
                api_url,
                headers=headers,
                params={'limit': 1},
                timeout=10
            )
            
            if response.status_code == 200:
                self.print_test(
                    "Cassanova API",
                    "PASS",
                    "Connessione API riuscita"
                )
                return True
            else:
                self.print_test(
                    "Cassanova API",
                    "FAIL",
                    f"Errore API: {response.status_code}",
                    response.text[:200]
                )
                return False
                
        except Exception as e:
            self.print_test(
                "Cassanova API",
                "FAIL",
                "Errore nel test API",
                str(e)
            )
            return False
    
    def fix_demo_user_password(self):
        """Ripara la password dell'utente demo"""
        self.print_header("FIX: DEMO USER PASSWORD")
        
        if not self.db_connection:
            print(f"{Fore.RED}Errore: Nessuna connessione al database{Style.RESET_ALL}")
            return False
        
        try:
            cursor = self.db_connection.cursor()
            
            # Genera nuovo hash
            new_hash = bcrypt.hashpw(
                DEMO_USER['password'].encode('utf-8'),
                bcrypt.gensalt()
            ).decode('utf-8')
            
            # Trova tenant_id
            cursor.execute(
                "SELECT id FROM tenants WHERE codice = %s",
                (DEMO_USER['tenant_code'],)
            )
            tenant = cursor.fetchone()
            
            if not tenant:
                print(f"{Fore.RED}Errore: Tenant DEMO non trovato{Style.RESET_ALL}")
                return False
            
            tenant_id = tenant[0]
            
            # Aggiorna password
            cursor.execute(
                """UPDATE tenant_users 
                   SET password_hash = %s
                   WHERE email = %s AND id_tenant = %s""",
                (new_hash, DEMO_USER['email'], tenant_id)
            )
            
            self.db_connection.commit()
            
            print(f"{Fore.GREEN}✓ Password aggiornata con successo{Style.RESET_ALL}")
            print(f"  Email: {DEMO_USER['email']}")
            print(f"  Password: {DEMO_USER['password']}")
            
            return True
            
        except Exception as e:
            print(f"{Fore.RED}Errore nell'aggiornamento password: {str(e)}{Style.RESET_ALL}")
            return False
    
    def print_summary(self):
        """Stampa riepilogo risultati"""
        self.print_header("RIEPILOGO DIAGNOSTICA")
        
        total = self.results['passed'] + self.results['failed'] + self.results['warnings']
        
        print(f"Test eseguiti: {total}")
        print(f"{Fore.GREEN}Superati: {self.results['passed']}{Style.RESET_ALL}")
        print(f"{Fore.RED}Falliti: {self.results['failed']}{Style.RESET_ALL}")
        print(f"{Fore.YELLOW}Warning: {self.results['warnings']}{Style.RESET_ALL}")
        
        if self.results['failed'] == 0:
            print(f"\n{Fore.GREEN}{'=' * 70}")
            print(f"{Fore.GREEN}SISTEMA OPERATIVO CORRETTAMENTE")
            print(f"{Fore.GREEN}{'=' * 70}{Style.RESET_ALL}")
        else:
            print(f"\n{Fore.RED}{'=' * 70}")
            print(f"{Fore.RED}ATTENZIONE: SONO PRESENTI ERRORI")
            print(f"{Fore.RED}{'=' * 70}{Style.RESET_ALL}")
    
    def run_all_tests(self):
        """Esegue tutti i test"""
        print(f"{Fore.CYAN}")
        print("╔═══════════════════════════════════════════════════════════════════╗")
        print("║          ENIGMA INVENTARIO - DIAGNOSTICA COMPLETA                 ║")
        print("║                                                                   ║")
        print(f"║  Data: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}                                    ║")
        print("╚═══════════════════════════════════════════════════════════════════╝")
        print(f"{Style.RESET_ALL}")
        
        # Esegui test
        db_ok = self.test_database_connection()
        
        if db_ok:
            self.test_database_structure()
            self.test_demo_user()
        
        self.test_flask_endpoints()
        self.test_authentication_flow()
        
        if db_ok:
            self.test_cassanova_api()
        
        # Chiudi connessione DB
        if self.db_connection:
            self.db_connection.close()
        
        # Riepilogo
        self.print_summary()
        
        return self.results['failed'] == 0


def main():
    """Entry point"""
    import argparse
    
    parser = argparse.ArgumentParser(
        description='ENIGMA Inventario - Script di Diagnostica'
    )
    parser.add_argument(
        '--verbose', '-v',
        action='store_true',
        help='Output dettagliato'
    )
    parser.add_argument(
        '--fix-demo-user',
        action='store_true',
        help='Ripara la password dell\'utente demo'
    )
    
    args = parser.parse_args()
    
    tester = DiagnosticTester(verbose=args.verbose)
    
    if args.fix_demo_user:
        if not tester.test_database_connection():
            sys.exit(1)
        success = tester.fix_demo_user_password()
        sys.exit(0 if success else 1)
    else:
        success = tester.run_all_tests()
        sys.exit(0 if success else 1)


if __name__ == '__main__':
    main()
