"""
BTC Transfer System for wallet_data.db
Handles transfers between any type of Bitcoin addresses (legacy, SegWit, or native SegWit)
"""
import sqlite3
import json
import time
import re
from datetime import datetime
from typing import Optional, Dict, Any
from pathlib import Path

class WalletTransfer:
    def __init__(self, db_path="wallet_data.db"):
        self.db_path = db_path
        self.conn = self._connect_db()
        self._init_database()
        
    def _init_database(self):
        """Initialize database tables if they don't exist"""
        cursor = self.conn.cursor()
        
        # Create wallets table if not exists
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS wallets (
                address TEXT PRIMARY KEY,
                balance REAL DEFAULT 0,
                total_mined REAL DEFAULT 0,
                metadata TEXT
            )
        ''')
        
        # Create transactions table if not exists
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS transactions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                from_address TEXT,
                to_address TEXT,
                amount REAL,
                timestamp REAL,
                status TEXT,
                tx_type TEXT,
                FOREIGN KEY (from_address) REFERENCES wallets(address),
                FOREIGN KEY (to_address) REFERENCES wallets(address)
            )
        ''')
        
        self.conn.commit()
        
    def _is_valid_address(self, address: str) -> bool:
        """Validate Bitcoin address format"""
        # Legacy address format (1...)
        legacy_pattern = re.compile('^[1][a-km-zA-HJ-NP-Z1-9]{25,34}$')
        # SegWit address format (3...)
        segwit_pattern = re.compile('^[3][a-km-zA-HJ-NP-Z1-9]{25,34}$')
        # Native SegWit address format (bc1...)
        bech32_pattern = re.compile('^bc1[a-zA-HJ-NP-Z0-9]{25,39}$')
        
        return bool(
            legacy_pattern.match(address) or 
            segwit_pattern.match(address) or 
            bech32_pattern.match(address)
        )
    def __init__(self, db_path="wallet_data.db"):
        self.db_path = db_path
        self.conn = self._connect_db()
        
    def _connect_db(self):
        """Connect to the wallet database"""
        try:
            return sqlite3.connect(self.db_path)
        except sqlite3.Error as e:
            print(f"Error connecting to database: {e}")
            raise

    def get_wallet_balance(self, address: str) -> Optional[float]:
        """Get wallet balance"""
        if not self._is_valid_address(address):
            print(f"Invalid Bitcoin address format: {address}")
            return None
            
        cursor = self.conn.cursor()
        cursor.execute("SELECT balance FROM wallets WHERE address = ?", (address,))
        result = cursor.fetchone()
        
        if result is None:
            # Auto-create wallet if it doesn't exist
            print(f"Wallet {address} not found. Creating new wallet...")
            cursor.execute("""
                INSERT INTO wallets (address, balance, total_mined, metadata)
                VALUES (?, 0, 0, ?)
            """, (address, json.dumps({
                'created_at': time.time(),
                'last_updated': time.time()
            })))
            self.conn.commit()
            return 0.0
            
        return float(result[0])

    def validate_transfer(self, from_address: str, amount: float) -> bool:
        """Validate if transfer is possible"""
        balance = self.get_wallet_balance(from_address)
        if balance is None:
            print("Source wallet not found!")
            return False
        if balance < amount:
            print(f"Insufficient funds! Balance: {balance}, Required: {amount}")
            return False
        return True

    def update_wallet_balance(self, address: str, amount: float, is_sender: bool = False):
        """Update wallet balance and metadata"""
        if not self._is_valid_address(address):
            print(f"Invalid Bitcoin address format: {address}")
            return False
            
        cursor = self.conn.cursor()
        
        # Get current wallet data
        cursor.execute("SELECT balance, metadata FROM wallets WHERE address = ?", (address,))
        current = cursor.fetchone()
        if not current:
            print(f"Wallet not found: {address}")
            return False

        current_balance, metadata_str = current
        metadata = json.loads(metadata_str)
        
        # Update balance
        new_balance = float(current_balance) - amount if is_sender else float(current_balance) + amount
        
        # Update metadata
        metadata.update({
            'last_transaction': time.time(),
            'last_transaction_amount': amount,
            'last_transaction_type': 'send' if is_sender else 'receive'
        })
        
        # Save changes
        cursor.execute("""
            UPDATE wallets 
            SET balance = ?, metadata = ?
            WHERE address = ?
        """, (new_balance, json.dumps(metadata), address))
        
        self.conn.commit()
        return True

    def transfer_btc(self, from_address: str, to_address: str, amount: float) -> bool:
        """Transfer BTC between wallets"""
        try:
            # Input validation
            if amount <= 0:
                print("Amount must be greater than 0")
                return False
                
            if from_address == to_address:
                print("Cannot transfer to same wallet")
                return False

            # Check if both wallets exist
            if not self.get_wallet_balance(from_address):
                print(f"Source wallet not found: {from_address}")
                return False
                
            if not self.get_wallet_balance(to_address):
                print(f"Destination wallet not found: {to_address}")
                return False

            # Validate sufficient balance
            if not self.validate_transfer(from_address, amount):
                return False

            # Perform transfer
            self.update_wallet_balance(from_address, amount, is_sender=True)
            self.update_wallet_balance(to_address, amount, is_sender=False)

            # Record transaction
            cursor = self.conn.cursor()
            cursor.execute("""
                INSERT INTO transactions 
                (from_address, to_address, amount, timestamp, status)
                VALUES (?, ?, ?, ?, ?)
            """, (from_address, to_address, amount, time.time(), 'completed'))
            
            self.conn.commit()
            
            print(f"\nTransfer successful!")
            print(f"From: {from_address}")
            print(f"To: {to_address}")
            print(f"Amount: {amount} BTC")
            print(f"New balances:")
            print(f"Sender: {self.get_wallet_balance(from_address)} BTC")
            print(f"Receiver: {self.get_wallet_balance(to_address)} BTC")
            
            return True

        except Exception as e:
            print(f"Transfer failed: {str(e)}")
            self.conn.rollback()
            return False

    def get_transaction_history(self, address: str):
        """Get transaction history for a wallet"""
        cursor = self.conn.cursor()
        cursor.execute("""
            SELECT * FROM transactions 
            WHERE from_address = ? OR to_address = ?
            ORDER BY timestamp DESC
        """, (address, address))
        
        transactions = cursor.fetchall()
        
        if transactions:
            print(f"\nTransaction History for {address}:")
            print("-" * 50)
            for tx in transactions:
                tx_time = datetime.fromtimestamp(tx[3]).strftime('%Y-%m-%d %H:%M:%S')
                print(f"Transaction ID: {tx[0]}")
                print(f"From: {tx[1]}")
                print(f"To: {tx[2]}")
                print(f"Amount: {tx[3]} BTC")
                print(f"Time: {tx_time}")
                print(f"Status: {tx[4]}")
                print("-" * 30)
        else:
            print(f"\nNo transactions found for {address}")

    def close(self):
        """Close database connection"""
        self.conn.close()

def main():
    transfer = WalletTransfer()
    
    while True:
        print("\nBTC Transfer System")
        print("1. View wallet balance")
        print("2. Make transfer")
        print("3. View transaction history")
        print("4. Exit")
        
        choice = input("\nEnter your choice (1-4): ")
        
        if choice == '1':
            address = input("Enter wallet address: ")
            balance = transfer.get_wallet_balance(address)
            if balance is not None:
                print(f"Balance: {balance} BTC")
            else:
                print("Wallet not found")
                
        elif choice == '2':
            from_addr = input("Enter sender's wallet address: ")
            to_addr = input("Enter receiver's wallet address: ")
            try:
                amount = float(input("Enter amount to transfer: "))
                transfer.transfer_btc(from_addr, to_addr, amount)
            except ValueError:
                print("Invalid amount")
                
        elif choice == '3':
            address = input("Enter wallet address: ")
            transfer.get_transaction_history(address)
            
        elif choice == '4':
            print("\nExiting...")
            break
            
        else:
            print("\nInvalid choice. Please try again.")
    
    transfer.close()

if __name__ == '__main__':
    main()
