"""
Gestion de l'authentification et des utilisateurs Web Sentinel
"""

import sqlite3
import hashlib
import secrets
import jwt
from datetime import datetime, timedelta
from functools import wraps
from flask import request, jsonify
import os

SECRET_KEY = os.getenv('JWT_SECRET_KEY', 'web-sentinel-secret-change-in-production')

class UserManager:
    """Gestionnaire des utilisateurs et authentification"""
    
    def __init__(self, db_path="/app/data/users.db"):
        self.db_path = db_path
        os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
        self.init_database()
    
    def init_database(self):
        """Initialiser la base de données des utilisateurs"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # Table des utilisateurs
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                email TEXT UNIQUE NOT NULL,
                password_hash TEXT NOT NULL,
                tier TEXT DEFAULT 'free',
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                last_login TIMESTAMP,
                active BOOLEAN DEFAULT 1
            )
        ''')
        
        # Table des licences utilisateurs
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS user_licenses (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER NOT NULL,
                license_key TEXT UNIQUE NOT NULL,
                tier TEXT NOT NULL,
                expires_at TIMESTAMP,
                active BOOLEAN DEFAULT 1,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (user_id) REFERENCES users (id)
            )
        ''')
        
        conn.commit()
        conn.close()
    
    def hash_password(self, password):
        """Hasher un mot de passe avec SHA-256 + salt"""
        salt = secrets.token_hex(16)
        pwd_hash = hashlib.sha256((password + salt).encode()).hexdigest()
        return f"{salt}${pwd_hash}"
    
    def verify_password(self, password, stored_hash):
        """Vérifier un mot de passe"""
        try:
            salt, pwd_hash = stored_hash.split('$')
            return hashlib.sha256((password + salt).encode()).hexdigest() == pwd_hash
        except:
            return False
    
    def create_user(self, name, email, password):
        """Créer un nouvel utilisateur"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        try:
            # Vérifier si l'email existe déjà
            cursor.execute('SELECT id FROM users WHERE email = ?', (email,))
            if cursor.fetchone():
                return {'success': False, 'error': 'Cet email est déjà utilisé'}
            
            # Créer l'utilisateur
            password_hash = self.hash_password(password)
            cursor.execute('''
                INSERT INTO users (name, email, password_hash)
                VALUES (?, ?, ?)
            ''', (name, email, password_hash))
            
            user_id = cursor.lastrowid
            conn.commit()
            
            # Générer un token JWT
            token = self.generate_token(user_id, email, name)
            
            return {
                'success': True,
                'token': token,
                'user_id': user_id,
                'name': name,
                'email': email
            }
            
        except Exception as e:
            conn.rollback()
            return {'success': False, 'error': str(e)}
        finally:
            conn.close()
    
    def authenticate_user_postgres(self, email, password):
        """
        Authentifier via PostgreSQL (nouvelle architecture unifiée)
        Retourne un dict avec success, token, user_id, etc.
        """
        try:
            import psycopg2
            conn = psycopg2.connect(
                host="web-sentinel-db",
                port=5432,
                database="websentinel_prod",
                user="websentinel_user",
                password="WebSentinelDB2025!"
            )
            cursor = conn.cursor()
            
            cursor.execute("""
                SELECT id, name, email, password_hash, tier, is_active
                FROM users WHERE email = %s
            """, (email,))
            
            user = cursor.fetchone()
            cursor.close()
            conn.close()
            
            if not user:
                return None
            
            user_id, name, email, password_hash, tier, is_active = user
            
            if not is_active:
                return {'success': False, 'error': 'Compte désactivé'}
            
            # SÉCURITÉ : Vérifier le mot de passe (OBLIGATOIRE pour authentification web)
            if not password_hash:
                return {'success': False, 'error': 'Compte sans mot de passe - utilisez API key'}
            
            if not self.verify_password(password, password_hash):
                return {'success': False, 'error': 'Email ou mot de passe incorrect'}
            
            # Générer token
            token = self.generate_token(user_id, email, name, tier)
            
            return {
                'success': True,
                'token': token,
                'user_id': user_id,
                'name': name,
                'email': email,
                'tier': tier
            }
            
        except Exception as e:
            print(f"Erreur auth PostgreSQL: {e}")
            return None
    
    def authenticate_user(self, email, password, sysop_keys=None):
        """
        Authentifier un utilisateur
        
        Args:
            email: Email de l'utilisateur
            password: Mot de passe
            sysop_keys: DEPRECATED - utilise maintenant PostgreSQL
        """
        # 1. Essayer d'abord PostgreSQL (nouvelle architecture)
        result = self.authenticate_user_postgres(email, password)
        if result:
            return result
        
        # 2. Fallback sur SQLite (pour compatibilité temporaire)
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        try:
            cursor.execute('''
                SELECT id, name, email, password_hash, tier, active
                FROM users WHERE email = ?
            ''', (email,))
            
            user = cursor.fetchone()
            if not user:
                return {'success': False, 'error': 'Email ou mot de passe incorrect'}
            
            user_id, name, email, password_hash, tier, active = user
            
            if not active:
                return {'success': False, 'error': 'Compte désactivé'}
            
            if not self.verify_password(password, password_hash):
                return {'success': False, 'error': 'Email ou mot de passe incorrect'}
            
            # Mettre à jour last_login
            cursor.execute('''
                UPDATE users SET last_login = CURRENT_TIMESTAMP
                WHERE id = ?
            ''', (user_id,))
            conn.commit()
            
            # Générer un token JWT
            token = self.generate_token(user_id, email, name, tier)
            
            return {
                'success': True,
                'token': token,
                'user_id': user_id,
                'name': name,
                'email': email,
                'tier': tier
            }
            
        except Exception as e:
            return {'success': False, 'error': str(e)}
        finally:
            conn.close()
    
    def generate_token(self, user_id, email, name, tier='free'):
        """Générer un token JWT"""
        payload = {
            'user_id': user_id,
            'email': email,
            'name': name,
            'tier': tier,
            'exp': datetime.utcnow() + timedelta(days=30)  # Token valide 30 jours
        }
        return jwt.encode(payload, SECRET_KEY, algorithm='HS256')
    
    def verify_token(self, token):
        """Vérifier un token JWT"""
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
            return {'success': True, 'data': payload}
        except jwt.ExpiredSignatureError:
            return {'success': False, 'error': 'Token expiré'}
        except jwt.InvalidTokenError:
            return {'success': False, 'error': 'Token invalide'}
    
    def get_user_licenses(self, user_id):
        """Récupérer les licences d'un utilisateur"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        try:
            cursor.execute('''
                SELECT license_key, tier, expires_at, active, created_at
                FROM user_licenses
                WHERE user_id = ?
                ORDER BY created_at DESC
            ''', (user_id,))
            
            licenses = []
            for row in cursor.fetchall():
                licenses.append({
                    'key': row[0],
                    'tier': row[1],
                    'expires_at': row[2],
                    'active': bool(row[3]),
                    'created_at': row[4]
                })
            
            return {'success': True, 'licenses': licenses}
            
        except Exception as e:
            return {'success': False, 'error': str(e)}
        finally:
            conn.close()
    
    def add_license_to_user(self, user_id, license_key, tier, expires_at=None):
        """Ajouter une licence à un utilisateur"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        try:
            cursor.execute('''
                INSERT INTO user_licenses (user_id, license_key, tier, expires_at)
                VALUES (?, ?, ?, ?)
            ''', (user_id, license_key, tier, expires_at))
            
            conn.commit()
            return {'success': True}
            
        except sqlite3.IntegrityError:
            return {'success': False, 'error': 'Licence déjà utilisée'}
        except Exception as e:
            conn.rollback()
            return {'success': False, 'error': str(e)}
        finally:
            conn.close()

def require_auth(f):
    """Décorateur pour protéger les routes nécessitant une authentification"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        token = None
        
        # Récupérer le token depuis le header Authorization
        if 'Authorization' in request.headers:
            auth_header = request.headers['Authorization']
            try:
                token = auth_header.split(' ')[1]  # Format: "Bearer TOKEN"
            except IndexError:
                return jsonify({'error': 'Format du token invalide'}), 401
        
        if not token:
            return jsonify({'error': 'Token manquant'}), 401
        
        # Vérifier le token
        user_manager = UserManager()
        result = user_manager.verify_token(token)
        
        if not result['success']:
            return jsonify({'error': result['error']}), 401
        
        # Ajouter les données utilisateur à la requête
        request.current_user = result['data']
        return f(*args, **kwargs)
    
    return decorated_function
