#!/usr/bin/env python3
"""
Script per visualizzare i dati P2PK dal database
Genera un report HTML interattivo
"""

import sqlite3
import sys
from datetime import datetime
from pathlib import Path

class P2PKDatabaseViewer:
    def __init__(self, db_path: str = "bitcoin_p2pk_study.db"):
        self.db_path = db_path

    def check_database_exists(self) -> bool:
        """Verifica se il database esiste"""
        return Path(self.db_path).exists()

    def get_statistics(self) -> dict:
        """Ottieni statistiche dal database"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()

        stats = {}

        try:
            # Progresso scansione
            cursor.execute('SELECT last_scanned_block, total_p2pk_found FROM scan_progress WHERE id = 1')
            progress = cursor.fetchone()
            stats['last_block'] = progress[0] if progress else 0
            stats['total_found'] = progress[1] if progress else 0

            # Totale P2PK nel database
            cursor.execute('SELECT COUNT(*) FROM p2pk_addresses')
            stats['total_in_db'] = cursor.fetchone()[0]

            # Range blocchi
            cursor.execute('SELECT MIN(block_height), MAX(block_height) FROM p2pk_addresses')
            min_block, max_block = cursor.fetchone()
            stats['min_block'] = min_block if min_block is not None else 0
            stats['max_block'] = max_block if max_block is not None else 0

            # Blocchi unici con P2PK
            cursor.execute('SELECT COUNT(DISTINCT block_height) FROM p2pk_addresses')
            stats['unique_blocks'] = cursor.fetchone()[0]

            # Transazioni unique
            cursor.execute('SELECT COUNT(DISTINCT txid) FROM p2pk_addresses')
            stats['unique_txs'] = cursor.fetchone()[0]

            # P2PK non spesi (con saldo attuale)
            cursor.execute('SELECT COUNT(*) FROM p2pk_addresses WHERE is_unspent = 1')
            stats['unspent_count'] = cursor.fetchone()[0]

            # Valore totale - calcolo manuale per evitare overflow
            cursor.execute('SELECT value_satoshi FROM p2pk_addresses')
            all_values = cursor.fetchall()
            total_sat = 0.0
            for (val,) in all_values:
                if val is not None:
                    total_sat += float(val)

            stats['total_value_btc'] = total_sat / 100000000.0
            stats['total_value_sat'] = int(total_sat)

            # Valore non speso
            cursor.execute('SELECT value_satoshi FROM p2pk_addresses WHERE is_unspent = 1')
            unspent_values = cursor.fetchall()
            unspent_sat = 0.0
            for (val,) in unspent_values:
                if val is not None:
                    unspent_sat += float(val)

            stats['unspent_value_btc'] = unspent_sat / 100000000.0
            stats['unspent_value_sat'] = int(unspent_sat)

            # Conta chiavi compresse vs non compresse
            cursor.execute('SELECT scriptpubkey FROM p2pk_addresses')
            all_scripts = cursor.fetchall()
            compressed_count = 0
            uncompressed_count = 0
            for (script,) in all_scripts:
                if script and script.startswith('41') and len(script) == 134:
                    uncompressed_count += 1
                elif script and script.startswith('21') and len(script) == 70:
                    compressed_count += 1

            stats['compressed_count'] = compressed_count
            stats['uncompressed_count'] = uncompressed_count

        except Exception as e:
            print(f"⚠️  Errore nel calcolo statistiche: {e}")
            import traceback
            traceback.print_exc()
            stats = {
                'last_block': 0,
                'total_found': 0,
                'total_in_db': 0,
                'min_block': 0,
                'max_block': 0,
                'unique_blocks': 0,
                'total_value_btc': 0.0,
                'total_value_sat': 0,
                'unique_txs': 0,
                'unspent_count': 0,
                'unspent_value_btc': 0.0,
                'unspent_value_sat': 0,
                'compressed_count': 0,
                'uncompressed_count': 0
            }

        conn.close()
        return stats

    def get_all_p2pk(self, limit: int = None) -> list:
        """Ottieni tutti i P2PK dal database"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()

        query = '''
            SELECT id, block_height, txid, output_index,
                   scriptpubkey, value_satoshi, timestamp, is_unspent, last_checked
            FROM p2pk_addresses
            ORDER BY block_height ASC, id ASC
        '''

        if limit:
            query += f' LIMIT {limit}'

        cursor.execute(query)
        results = cursor.fetchall()
        conn.close()

        return results

    def extract_pubkey_from_script(self, scriptpubkey: str) -> str:
        """Estrae la chiave pubblica dallo scriptPubKey"""
        if not scriptpubkey:
            return ""

        # P2PK non compresso: 41 + pubkey (130 hex chars) + ac
        if scriptpubkey.startswith('41') and len(scriptpubkey) == 134:
            return scriptpubkey[2:132]  # Rimuovi 41 all'inizio e ac alla fine

        # P2PK compresso: 21 + pubkey (66 hex chars) + ac
        elif scriptpubkey.startswith('21') and len(scriptpubkey) == 70:
            return scriptpubkey[2:68]  # Rimuovi 21 all'inizio e ac alla fine

        return scriptpubkey

    def _generate_table_html(self, p2pk_data: list) -> str:
        """Genera l'HTML della tabella"""
        if not p2pk_data:
            return '<div class="no-data">📭 Nessun dato P2PK trovato nel database</div>'

        rows_html = []
        for row in p2pk_data:
            scriptpubkey = row[4]
            pubkey = self.extract_pubkey_from_script(scriptpubkey)
            txid_short = row[2][:16] if len(row[2]) > 16 else row[2]
            timestamp_str = datetime.fromtimestamp(row[6]).strftime('%Y-%m-%d %H:%M') if row[6] else 'N/A'
            # row[5] è già in satoshi, lo convertiamo in BTC dividendo per 100000000
            value_satoshi = row[5]
            value_btc = value_satoshi / 100000000.0

            # Stato UTXO (row[7] = is_unspent)
            is_unspent = row[7] if len(row) > 7 else 0
            utxo_status = '🟢 NON SPESO' if is_unspent else '🔴 SPESO'
            utxo_class = 'unspent' if is_unspent else 'spent'

            # Determina se la chiave è compressa o non compressa
            if scriptpubkey and scriptpubkey.startswith('41') and len(scriptpubkey) == 134:
                key_type = 'uncompressed'
                key_type_badge = '<span class="key-type-badge uncompressed">📜 Non Compressa (65 bytes)</span>'
            elif scriptpubkey and scriptpubkey.startswith('21') and len(scriptpubkey) == 70:
                key_type = 'compressed'
                key_type_badge = '<span class="key-type-badge compressed">📦 Compressa (33 bytes)</span>'
            else:
                key_type = 'unknown'
                key_type_badge = '<span class="key-type-badge unknown">❓ Sconosciuta</span>'

            row_html = f'''
                    <tr class="{utxo_class} {key_type}">
                        <td>{row[0]}</td>
                        <td><span class="block">{row[1]}</span></td>
                        <td>
                            <span class="txid">{txid_short}...</span>
                            <button class="copy-btn" onclick="copyToClipboard('{row[2]}')">📋</button>
                        </td>
                        <td>{row[3]}</td>
                        <td>
                            <div class="pubkey">
                                {key_type_badge}
                                <div style="margin-top: 5px;">{pubkey}</div>
                                <button class="copy-btn" onclick="copyToClipboard('{pubkey}')">📋</button>
                            </div>
                        </td>
                        <td class="value">{value_btc:.8f} BTC<br><small>({value_satoshi:,} sat)</small></td>
                        <td><span class="status-badge {utxo_class}">{utxo_status}</span></td>
                        <td>{timestamp_str}</td>
                    </tr>'''
            rows_html.append(row_html)

        return f'''
            <table id="dataTable">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Blocco</th>
                        <th>TXID</th>
                        <th>Output</th>
                        <th>Chiave Pubblica</th>
                        <th>Valore (BTC)</th>
                        <th>Stato UTXO</th>
                        <th>Timestamp</th>
                    </tr>
                </thead>
                <tbody>
                    {''.join(rows_html)}
                </tbody>
            </table>'''

    def generate_html_report(self, output_file: str = "p2pk_report.html"):
        """Genera un report HTML interattivo"""
        if not self.check_database_exists():
            print(f"❌ Database non trovato: {self.db_path}")
            return

        stats = self.get_statistics()
        p2pk_data = self.get_all_p2pk()

        html = f"""<!DOCTYPE html>
<html lang="it">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>P2PK Database Report</title>
    <style>
        * {{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }}

        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            padding: 20px;
            color: #333;
        }}

        .container {{
            max-width: 1400px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            overflow: hidden;
        }}

        .header {{
            background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }}

        .header h1 {{
            font-size: 2.5em;
            margin-bottom: 10px;
        }}

        .header p {{
            opacity: 0.9;
            font-size: 1.1em;
        }}

        .stats {{
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            padding: 30px;
            background: #f8f9fa;
        }}

        .stat-card {{
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            text-align: center;
            transition: transform 0.3s;
        }}

        .stat-card:hover {{
            transform: translateY(-5px);
            box-shadow: 0 5px 20px rgba(0,0,0,0.2);
        }}

        .stat-card .label {{
            color: #666;
            font-size: 0.9em;
            text-transform: uppercase;
            letter-spacing: 1px;
            margin-bottom: 10px;
        }}

        .stat-card .value {{
            font-size: 2em;
            font-weight: bold;
            color: #667eea;
        }}

        .content {{
            padding: 30px;
        }}

        .search-box {{
            margin-bottom: 20px;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 10px;
        }}

        .search-box input {{
            width: 100%;
            padding: 12px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 1em;
            transition: border-color 0.3s;
        }}

        .search-box input:focus {{
            outline: none;
            border-color: #667eea;
        }}

        .filter-buttons {{
            margin: 20px 0;
            text-align: center;
        }}

        .filter-btn {{
            padding: 10px 20px;
            margin: 0 5px;
            border: 2px solid #667eea;
            background: white;
            color: #667eea;
            border-radius: 20px;
            cursor: pointer;
            font-weight: bold;
            font-size: 0.95em;
            transition: all 0.3s;
        }}

        .filter-btn:hover {{
            background: #f0f0f0;
        }}

        .filter-btn.active {{
            background: #667eea;
            color: white;
        }}

        .filter-btn.unspent-filter.active {{
            background: #28a745;
            border-color: #28a745;
        }}

        .filter-btn.spent-filter.active {{
            background: #dc3545;
            border-color: #dc3545;
        }}

        table {{
            width: 100%;
            border-collapse: collapse;
            background: white;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            border-radius: 10px;
            overflow: hidden;
        }}

        thead {{
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
        }}

        th {{
            padding: 15px;
            text-align: left;
            font-weight: 600;
            text-transform: uppercase;
            font-size: 0.9em;
            letter-spacing: 1px;
        }}

        td {{
            padding: 12px 15px;
            border-bottom: 1px solid #f0f0f0;
        }}

        tr:hover {{
            background: #f8f9fa;
        }}

        .pubkey {{
            font-family: 'Courier New', monospace;
            font-size: 0.85em;
            color: #e74c3c;
            word-break: break-all;
            background: #fff3cd;
            padding: 5px;
            border-radius: 4px;
        }}

        .txid {{
            font-family: 'Courier New', monospace;
            font-size: 0.85em;
            color: #3498db;
        }}

        .block {{
            background: #667eea;
            color: white;
            padding: 5px 10px;
            border-radius: 20px;
            display: inline-block;
            font-weight: bold;
        }}

        .value {{
            color: #27ae60;
            font-weight: bold;
        }}

        .footer {{
            background: #f8f9fa;
            padding: 20px;
            text-align: center;
            color: #666;
            font-size: 0.9em;
        }}

        .copy-btn {{
            background: #667eea;
            color: white;
            border: none;
            padding: 5px 10px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 0.8em;
            margin-left: 5px;
        }}

        .copy-btn:hover {{
            background: #764ba2;
        }}

        .no-data {{
            text-align: center;
            padding: 50px;
            color: #999;
            font-size: 1.2em;
        }}

        .status-badge {{
            padding: 5px 12px;
            border-radius: 20px;
            font-size: 0.85em;
            font-weight: bold;
            display: inline-block;
        }}

        .status-badge.unspent {{
            background: #d4edda;
            color: #155724;
        }}

        .status-badge.spent {{
            background: #f8d7da;
            color: #721c24;
        }}

        tr.unspent {{
            background: #f0fff4;
        }}

        tr.spent {{
            opacity: 0.7;
        }}

        .key-type-badge {{
            padding: 4px 10px;
            border-radius: 15px;
            font-size: 0.8em;
            font-weight: bold;
            display: inline-block;
            margin-bottom: 5px;
        }}

        .key-type-badge.uncompressed {{
            background: #cfe2ff;
            color: #084298;
            border: 1px solid #9ec5fe;
        }}

        .key-type-badge.compressed {{
            background: #d1e7dd;
            color: #0a3622;
            border: 1px solid #a3cfbb;
        }}

        .key-type-badge.unknown {{
            background: #f8d7da;
            color: #58151c;
            border: 1px solid #f1aeb5;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🔐 P2PK Database Report</h1>
            <p>Bitcoin Pay-to-Public-Key Transaction Scanner</p>
            <p style="font-size: 0.9em; margin-top: 10px;">Database: {self.db_path}</p>
        </div>

        <div class="stats">
            <div class="stat-card">
                <div class="label">Ultimo Blocco</div>
                <div class="value">{stats['last_block']:,}</div>
            </div>
            <div class="stat-card">
                <div class="label">P2PK Trovati</div>
                <div class="value">{stats['total_in_db']:,}</div>
            </div>
            <div class="stat-card">
                <div class="label">Blocchi Unici</div>
                <div class="value">{stats['unique_blocks']:,}</div>
            </div>
            <div class="stat-card">
                <div class="label">Valore Totale</div>
                <div class="value">{stats['total_value_btc']:.8f} BTC</div>
            </div>
            <div class="stat-card">
                <div class="label">Range Blocchi</div>
                <div class="value">{stats['min_block']:,} - {stats['max_block']:,}</div>
            </div>
            <div class="stat-card">
                <div class="label">Transazioni Uniche</div>
                <div class="value">{stats['unique_txs']:,}</div>
            </div>
            <div class="stat-card" style="background: #d4edda;">
                <div class="label" style="color: #155724;">💰 P2PK Non Spesi</div>
                <div class="value" style="color: #155724;">{stats['unspent_count']:,}</div>
            </div>
            <div class="stat-card" style="background: #d1ecf1;">
                <div class="label" style="color: #0c5460;">💎 Valore Non Speso</div>
                <div class="value" style="color: #0c5460;">{stats['unspent_value_btc']:.8f} BTC</div>
            </div>
            <div class="stat-card" style="background: #cfe2ff;">
                <div class="label" style="color: #084298;">📜 Chiavi Non Compresse</div>
                <div class="value" style="color: #084298;">{stats['uncompressed_count']:,}</div>
            </div>
            <div class="stat-card" style="background: #d1e7dd;">
                <div class="label" style="color: #0a3622;">📦 Chiavi Compresse</div>
                <div class="value" style="color: #0a3622;">{stats['compressed_count']:,}</div>
            </div>
        </div>

        <div class="content">
            <div class="search-box">
                <input type="text" id="searchInput" placeholder="🔍 Cerca per blocco, txid, o chiave pubblica..." onkeyup="filterTable()">
            </div>

            <div class="filter-buttons">
                <button class="filter-btn active" onclick="filterByStatus('all')">🔍 Tutti i P2PK</button>
                <button class="filter-btn unspent-filter" onclick="filterByStatus('unspent')">🟢 Solo Non Spesi</button>
                <button class="filter-btn spent-filter" onclick="filterByStatus('spent')">🔴 Solo Spesi</button>
            </div>

            <div class="filter-buttons" style="margin-top: 10px;">
                <button class="filter-btn" onclick="filterByKeyType('all-keys')">🔑 Tutti i Tipi</button>
                <button class="filter-btn" onclick="filterByKeyType('uncompressed')">📜 Solo Non Compresse</button>
                <button class="filter-btn" onclick="filterByKeyType('compressed')">📦 Solo Compresse</button>
            </div>

            {self._generate_table_html(p2pk_data)}
        </div>

        <div class="footer">
            <p>Report generato il {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
            <p style="margin-top: 10px;">⚠️ Questo report è solo per scopi educativi e di ricerca</p>
        </div>
    </div>

    <script>
        function filterTable() {{
            const input = document.getElementById('searchInput');
            const filter = input.value.toUpperCase();
            const table = document.getElementById('dataTable');

            if (!table) return;

            const tr = table.getElementsByTagName('tr');

            for (let i = 1; i < tr.length; i++) {{
                const row = tr[i];
                const text = row.textContent || row.innerText;

                if (text.toUpperCase().indexOf(filter) > -1) {{
                    row.style.display = '';
                }} else {{
                    row.style.display = 'none';
                }}
            }}
        }}

        function copyToClipboard(text) {{
            navigator.clipboard.writeText(text).then(() => {{
                alert('✅ Copiato negli appunti!');
            }}).catch(err => {{
                console.error('Errore durante la copia:', err);
            }});
        }}

        function filterByStatus(status) {{
            const table = document.getElementById('dataTable');
            if (!table) return;

            const tr = table.getElementsByTagName('tr');
            const buttons = document.querySelectorAll('.filter-btn');

            // Aggiorna stato pulsanti
            buttons.forEach(btn => btn.classList.remove('active'));
            event.target.classList.add('active');

            // Filtra righe in base allo stato UTXO
            for (let i = 1; i < tr.length; i++) {{
                const row = tr[i];

                if (status === 'all') {{
                    row.style.display = '';
                }} else if (status === 'unspent') {{
                    row.style.display = row.classList.contains('unspent') ? '' : 'none';
                }} else if (status === 'spent') {{
                    row.style.display = row.classList.contains('spent') ? '' : 'none';
                }}
            }}
        }}

        function filterByKeyType(keyType) {{
            const table = document.getElementById('dataTable');
            if (!table) return;

            const tr = table.getElementsByTagName('tr');

            // Aggiorna stato pulsanti del gruppo key-type
            event.target.parentElement.querySelectorAll('.filter-btn').forEach(btn => {{
                btn.classList.remove('active');
            }});
            event.target.classList.add('active');

            // Filtra righe in base al tipo di chiave
            for (let i = 1; i < tr.length; i++) {{
                const row = tr[i];

                if (keyType === 'all-keys') {{
                    row.style.display = '';
                }} else if (keyType === 'uncompressed') {{
                    row.style.display = row.classList.contains('uncompressed') ? '' : 'none';
                }} else if (keyType === 'compressed') {{
                    row.style.display = row.classList.contains('compressed') ? '' : 'none';
                }}
            }}
        }}
    </script>
</body>
</html>
"""

        with open(output_file, 'w', encoding='utf-8') as f:
            f.write(html)

        print(f"✅ Report HTML generato: {output_file}")
        print(f"📊 Statistiche:")
        print(f"   - P2PK totali: {stats['total_in_db']}")
        print(f"   - Blocchi scansionati: {stats['last_block']}")
        print(f"   - Valore totale: {stats['total_value_btc']:.8f} BTC")

    def print_console_report(self):
        """Stampa un report nel terminale"""
        if not self.check_database_exists():
            print(f"❌ Database non trovato: {self.db_path}")
            return

        stats = self.get_statistics()

        print("\n" + "="*60)
        print("📊 REPORT DATABASE P2PK")
        print("="*60)
        print(f"📁 Database: {self.db_path}")
        print(f"📦 Ultimo blocco scansionato: {stats['last_block']:,}")
        print(f"🔑 P2PK totali trovati: {stats['total_in_db']:,}")
        print(f"📊 Blocchi unici con P2PK: {stats['unique_blocks']:,}")
        print(f"📈 Range blocchi: {stats['min_block']:,} - {stats['max_block']:,}")
        print(f"💰 Valore totale: {stats['total_value_btc']:.8f} BTC ({stats['total_value_sat']:,} sat)")
        print(f"📝 Transazioni uniche: {stats['unique_txs']:,}")
        print("-"*60)
        print(f"💎 P2PK NON SPESI: {stats['unspent_count']:,}")
        print(f"💵 Valore non speso: {stats['unspent_value_btc']:.8f} BTC ({stats['unspent_value_sat']:,} sat)")
        print("="*60)

        # Mostra alcuni esempi
        p2pk_data = self.get_all_p2pk(limit=5)
        if p2pk_data:
            print("\n🔍 Primi 5 P2PK trovati:")
            for row in p2pk_data:
                pubkey = self.extract_pubkey_from_script(row[4])
                print(f"\n  Blocco {row[1]} | TX: {row[2][:16]}...")
                print(f"  Pubkey: {pubkey[:40]}...")
                print(f"  Valore: {row[5] / 100000000:.8f} BTC")

if __name__ == "__main__":
    db_file = "bitcoin_p2pk_study.db"

    # Se viene passato un argomento, usalo come path del database
    if len(sys.argv) > 1:
        db_file = sys.argv[1]

    viewer = P2PKDatabaseViewer(db_file)

    print("🔐 P2PK Database Viewer")
    print("="*60)
    print("Scegli un'opzione:")
    print("1. Genera report HTML")
    print("2. Mostra report nel terminale")
    print("3. Entrambi")
    print("="*60)

    choice = input("Scelta (1/2/3): ").strip()

    if choice == "1":
        viewer.generate_html_report()
    elif choice == "2":
        viewer.print_console_report()
    elif choice == "3":
        viewer.generate_html_report()
        viewer.print_console_report()
    else:
        print("❌ Scelta non valida")
