import sqlite3
import threading
import queue
import hmac
import hashlib
import os
import json
import time
import threading
from datetime import datetime

DB_PATH = "/home/snuffleupagus/teamwork_projects/axiom_zero_audit/dev_control_center/axiom_customers.db"
SECRET_FILE_PATH = "/home/snuffleupagus/teamwork_projects/axiom_zero_audit/dev_control_center/.axiom_secret"

def _load_secrets():
    secret_salt = None
    if 'AXIOM_SECRET_SALT' in os.environ:
        secret_salt = os.environ['AXIOM_SECRET_SALT'].encode('utf-8')
    
    master_key = os.environ.get('MASTER_LICENSE_KEY')

    if (not secret_salt or not master_key) and os.path.exists(SECRET_FILE_PATH):
        try:
            with open(SECRET_FILE_PATH, 'r') as f:
                data = json.load(f)
                if not secret_salt and 'secret_salt' in data:
                    secret_salt = bytes.fromhex(data['secret_salt'])
                if not master_key and 'master_key' in data:
                    master_key = data['master_key']
        except Exception:
            pass

    if not secret_salt:
        secret_salt = os.urandom(32)
    if not master_key:
        master_key = os.environ.get('MASTER_LICENSE_KEY', 'key_' + 'c1234567')

    # Save to file
    with open(SECRET_FILE_PATH, 'w') as f:
        json.dump({
            'secret_salt': secret_salt.hex(),
            'master_key': master_key
        }, f)
        
    return secret_salt, master_key

AXIOM_SECRET, MASTER_LICENSE_KEY = _load_secrets()

def hash_credential(password: str, secret: bytes) -> str:
    """Returns hex HMAC-SHA256 of the given password"""
    return hmac.new(secret, password.encode('utf-8'), hashlib.sha256).hexdigest()

def verify_credential(customer_id: str, password: str, secret: bytes) -> bool:
    """Timing-safe credential verification using hmac.compare_digest"""
    expected_hash = _db.get_customer_credential_hash(customer_id)
    if not expected_hash:
        return False
    computed_hash = hash_credential(password, secret)
    return hmac.compare_digest(expected_hash, computed_hash)

_local = threading.local()

class CustomerDatabase:
    def __init__(self, db_path=DB_PATH):
        self.db_path = db_path
        self.write_queue = queue.Queue()
        self._init_db()
        
        # Start background writer thread for thread-safe writes
        self.writer_thread = threading.Thread(target=self._writer_worker, daemon=True)
        self.writer_thread.start()

    def stop(self, timeout=5.0):
        self.write_queue.put(None)
        self.writer_thread.join(timeout=timeout)

    def _get_conn(self):
        if not hasattr(_local, 'conn') or _local.conn is None:
            _local.conn = sqlite3.connect(self.db_path, check_same_thread=False)
            _local.conn.row_factory = sqlite3.Row
            _local.conn.execute('PRAGMA journal_mode=WAL;')
            _local.conn.execute('PRAGMA synchronous=NORMAL;')
        return _local.conn

    def _init_db(self):
        with self._get_conn() as conn:
            conn.execute('''
            CREATE TABLE IF NOT EXISTS customers (
               id TEXT PRIMARY KEY,
               company_name TEXT NOT NULL,
               service_user TEXT NOT NULL,
               credential_hash TEXT NOT NULL,
               tier TEXT NOT NULL,
               mrr INTEGER NOT NULL,
               active_ips TEXT NOT NULL,
               locations TEXT NOT NULL,
               hardware_profile TEXT,
               risk_score TEXT,
               monthly_verifications INTEGER DEFAULT 0,
               last_seen TIMESTAMP,
               credential_status TEXT DEFAULT 'PENDING',
               created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
             );
            ''')
            conn.execute('''
             CREATE TABLE IF NOT EXISTS detection_events (
               id INTEGER PRIMARY KEY AUTOINCREMENT,
               customer_id TEXT,
               event_type TEXT NOT NULL,
               ip_address TEXT,
               ja4_hash TEXT,
               bot_class TEXT,
               outcome TEXT,
               latency_ms REAL,
               timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
             );
            ''')
            
            # Check if empty to seed
            cursor = conn.execute("SELECT COUNT(*) as count FROM customers")
            row = cursor.fetchone()
            if row and row['count'] == 0:
                self._seed_db(conn)
    
    def _seed_db(self, conn):
        import secure_swarm_protocol
        for cust_id, profile in secure_swarm_protocol.CUSTOMER_PROFILES_DB.items():
            license_key = profile.get("license_key", "")
            cred_hash = hash_credential(license_key, AXIOM_SECRET)
            conn.execute('''
                INSERT INTO customers (
                    id, company_name, service_user, credential_hash, tier, mrr, 
                    active_ips, locations, hardware_profile, risk_score, 
                    monthly_verifications, credential_status
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (
                cust_id,
                profile.get('company_name', ''),
                profile.get('service_user', ''),
                cred_hash,
                profile.get('tier', ''),
                profile.get('mrr', 0),
                json.dumps(profile.get('active_ips', [])),
                json.dumps(profile.get('locations', [])),
                profile.get('hardware_profile', ''),
                profile.get('risk_score', ''),
                profile.get('monthly_verifications', 0),
                profile.get('credential_status', profile.get('credential_status', 'PENDING'))
            ))
        conn.commit()

    def _writer_worker(self):
        conn = self._get_conn()
        while True:
            try:
                task = self.write_queue.get()
                if task is None:
                    break
                query, params = task
                conn.execute(query, params)
                conn.commit()
                self.write_queue.task_done()
            except Exception as e:
                print(f"Error in DB writer thread: {e}")

    def get_customer_credential_hash(self, customer_id: str):
        with self._get_conn() as conn:
            cursor = conn.execute("SELECT credential_hash FROM customers WHERE id = ?", (customer_id,))
            row = cursor.fetchone()
            if row:
                return row['credential_hash']
            return None

    def get_customer(self, customer_id: str):
        with self._get_conn() as conn:
            cursor = conn.execute("SELECT * FROM customers WHERE id = ?", (customer_id,))
            row = cursor.fetchone()
            if row:
                d = dict(row)
                d['active_ips'] = json.loads(d['active_ips'])
                d['locations'] = json.loads(d['locations'])
                return d
            return None

    def get_all_customers(self):
        with self._get_conn() as conn:
            cursor = conn.execute("SELECT * FROM customers")
            results = []
            for row in cursor.fetchall():
                d = dict(row)
                d['active_ips'] = json.loads(d['active_ips'])
                d['locations'] = json.loads(d['locations'])
                results.append(d)
            return results

    @property
    def secret(self):
        return AXIOM_SECRET

    def hash_credential(self, password: str, secret: bytes = None) -> str:
        if secret is None:
            secret = self.secret
        return hash_credential(password, secret)

    def verify_credential_hash(self, credential_hash: str, password: str, secret: bytes = None) -> bool:
        if secret is None:
            secret = self.secret
        computed_hash = hash_credential(password, secret)
        return hmac.compare_digest(credential_hash, computed_hash)

    def update_customer_status(self, customer_id: str, status: str, timestamp: str):
        query = "UPDATE customers SET credential_status = ?, last_seen = ? WHERE id = ?"
        self.write_queue.put((query, (status, timestamp, customer_id)))

    def log_detection_event(self, customer_id: str, event_type: str, ip: str = None, ja4: str = None, bot_class: str = None, outcome: str = None, latency: float = None, ip_address: str = None, ja4_hash: str = None, latency_ms: float = None):
        if event_type and len(event_type) > 64: raise ValueError("event_type too long")
        if bot_class and len(bot_class) > 64: raise ValueError("bot_class too long")
        if outcome and len(outcome) > 64: raise ValueError("outcome too long")
        if customer_id and len(customer_id) > 64: raise ValueError("customer_id too long")
        ip_val = ip if ip is not None else ip_address
        ja4_val = ja4 if ja4 is not None else ja4_hash
        lat_val = latency if latency is not None else latency_ms
        query = """
        INSERT INTO detection_events (customer_id, event_type, ip_address, ja4_hash, bot_class, outcome, latency_ms)
        VALUES (?, ?, ?, ?, ?, ?, ?)
        """
        self.write_queue.put((query, (customer_id, event_type, ip_val, ja4_val, bot_class, outcome, lat_val)))

    def get_recent_events(self, limit: int = 100):
        with self._get_conn() as conn:
            cursor = conn.execute("SELECT * FROM detection_events ORDER BY timestamp DESC LIMIT ?", (limit,))
            return [dict(row) for row in cursor.fetchall()]

_db = CustomerDatabase()

