#!/usr/bin/env python3
"""
30-Day Sovereignty DCA Bot
Automated Bitcoin accumulation with risk controls
"""

import ccxt
import time
import os
import json
import sqlite3
from datetime import datetime
from dotenv import load_dotenv
import logging

# Load environment variables
load_dotenv()

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('dca_bot.log'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

class DCABot:
    """Dollar Cost Averaging Bot for Bitcoin accumulation"""

    def __init__(self):
        self.exchange = self._init_exchange()
        self.db_conn = self._init_database()

        # Configuration
        self.daily_amount_usd = float(os.getenv('DAILY_AMOUNT_USD', '10'))
        self.max_daily_percent = float(os.getenv('MAX_DAILY_PERCENT', '0.02'))
        self.stop_loss_percent = float(os.getenv('STOP_LOSS_PERCENT', '0.15'))
        self.trading_pair = os.getenv('TRADING_PAIR', 'BTC/USDT')

        logger.info(f"DCA Bot initialized - Daily amount: ${self.daily_amount_usd}")

    def _init_exchange(self):
        """Initialize Binance exchange connection"""
        try:
            exchange = ccxt.binance({
                'apiKey': os.getenv('BINANCE_API_KEY'),
                'secret': os.getenv('BINANCE_SECRET_KEY'),
                'enableRateLimit': True,
                'options': {
                    'defaultType': 'spot'
                }
            })

            # Test connection
            balance = exchange.fetch_balance()
            logger.info("✅ Successfully connected to Binance")
            return exchange

        except Exception as e:
            logger.error(f"❌ Failed to connect to Binance: {e}")
            raise

    def _init_database(self):
        """Initialize SQLite database for tracking"""
        conn = sqlite3.connect('dca_history.db')
        cursor = conn.cursor()

        cursor.execute('''
            CREATE TABLE IF NOT EXISTS transactions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp TEXT NOT NULL,
                pair TEXT NOT NULL,
                amount_usd REAL NOT NULL,
                btc_price REAL NOT NULL,
                btc_amount REAL NOT NULL,
                fee REAL NOT NULL,
                order_id TEXT,
                status TEXT NOT NULL,
                notes TEXT
            )
        ''')

        cursor.execute('''
            CREATE TABLE IF NOT EXISTS daily_stats (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                date TEXT NOT NULL UNIQUE,
                transactions_count INTEGER DEFAULT 0,
                total_usd_spent REAL DEFAULT 0,
                total_btc_accumulated REAL DEFAULT 0,
                avg_btc_price REAL DEFAULT 0,
                portfolio_value_usd REAL DEFAULT 0
            )
        ''')

        conn.commit()
        logger.info("✅ Database initialized")
        return conn

    def get_btc_price(self):
        """Get current BTC price"""
        try:
            ticker = self.exchange.fetch_ticker(self.trading_pair)
            return ticker['last']
        except Exception as e:
            logger.error(f"Error fetching BTC price: {e}")
            raise

    def get_portfolio_value(self):
        """Calculate current portfolio value in USD"""
        try:
            balance = self.exchange.fetch_balance()
            btc_balance = balance['BTC']['total']
            btc_price = self.get_btc_price()

            portfolio_value = btc_balance * btc_price
            logger.info(f"📊 Portfolio: {btc_balance:.8f} BTC = ${portfolio_value:.2f}")
            return portfolio_value

        except Exception as e:
            logger.error(f"Error calculating portfolio value: {e}")
            return 0

    def check_risk_controls(self):
        """Check risk controls before executing trade"""
        try:
            portfolio_value = self.get_portfolio_value()

            # Check stop loss
            if portfolio_value > 0:
                cursor = self.db_conn.cursor()
                cursor.execute('SELECT SUM(amount_usd) FROM transactions WHERE status = "completed"')
                total_invested = cursor.fetchone()[0] or 0

                if total_invested > 0:
                    current_loss = (total_invested - portfolio_value) / total_invested

                    if current_loss > self.stop_loss_percent:
                        logger.warning(f"⚠️ STOP LOSS TRIGGERED: {current_loss*100:.2f}% loss")
                        return False

            # Check daily spending limit (placeholder - needs credit API integration)
            logger.info("✅ Risk controls passed")
            return True

        except Exception as e:
            logger.error(f"Error checking risk controls: {e}")
            return False

    def execute_dca_purchase(self, amount_usd=None):
        """Execute DCA purchase"""
        if amount_usd is None:
            amount_usd = self.daily_amount_usd

        try:
            # Check risk controls
            if not self.check_risk_controls():
                logger.warning("🛑 Purchase blocked by risk controls")
                return False

            # Get current price
            btc_price = self.get_btc_price()
            btc_amount = amount_usd / btc_price

            logger.info(f"💰 Attempting to buy {btc_amount:.8f} BTC at ${btc_price:.2f}")

            # Execute market order
            order = self.exchange.create_market_buy_order(
                self.trading_pair,
                btc_amount
            )

            # Calculate fee
            fee = order.get('fee', {}).get('cost', 0)

            # Log transaction
            self._log_transaction(
                pair=self.trading_pair,
                amount_usd=amount_usd,
                btc_price=btc_price,
                btc_amount=order['filled'],
                fee=fee,
                order_id=order['id'],
                status='completed',
                notes=f"DCA purchase - {order['status']}"
            )

            logger.info(f"✅ Successfully bought {order['filled']:.8f} BTC")
            logger.info(f"📋 Order ID: {order['id']}")

            return True

        except ccxt.InsufficientFunds as e:
            logger.error(f"❌ Insufficient funds: {e}")
            self._log_transaction(
                pair=self.trading_pair,
                amount_usd=amount_usd,
                btc_price=self.get_btc_price(),
                btc_amount=0,
                fee=0,
                status='failed',
                notes=f"Insufficient funds: {e}"
            )
            return False

        except Exception as e:
            logger.error(f"❌ Purchase failed: {e}")
            self._log_transaction(
                pair=self.trading_pair,
                amount_usd=amount_usd,
                btc_price=self.get_btc_price(),
                btc_amount=0,
                fee=0,
                status='failed',
                notes=f"Error: {e}"
            )
            return False

    def _log_transaction(self, pair, amount_usd, btc_price, btc_amount, fee, status, order_id=None, notes=None):
        """Log transaction to database"""
        cursor = self.db_conn.cursor()

        cursor.execute('''
            INSERT INTO transactions
            (timestamp, pair, amount_usd, btc_price, btc_amount, fee, order_id, status, notes)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        ''', (
            datetime.now().isoformat(),
            pair,
            amount_usd,
            btc_price,
            btc_amount,
            fee,
            order_id,
            status,
            notes
        ))

        self.db_conn.commit()

    def update_daily_stats(self):
        """Update daily statistics"""
        cursor = self.db_conn.cursor()
        today = datetime.now().strftime('%Y-%m-%d')

        cursor.execute('''
            SELECT
                COUNT(*) as count,
                SUM(amount_usd) as total_usd,
                SUM(btc_amount) as total_btc,
                AVG(btc_price) as avg_price
            FROM transactions
            WHERE DATE(timestamp) = ? AND status = "completed"
        ''', (today,))

        stats = cursor.fetchone()

        cursor.execute('''
            INSERT OR REPLACE INTO daily_stats
            (date, transactions_count, total_usd_spent, total_btc_accumulated, avg_btc_price, portfolio_value_usd)
            VALUES (?, ?, ?, ?, ?, ?)
        ''', (
            today,
            stats[0] or 0,
            stats[1] or 0,
            stats[2] or 0,
            stats[3] or 0,
            self.get_portfolio_value()
        ))

        self.db_conn.commit()

    def get_statistics(self):
        """Get overall statistics"""
        cursor = self.db_conn.cursor()

        # Total stats
        cursor.execute('''
            SELECT
                COUNT(*) as total_transactions,
                SUM(amount_usd) as total_invested,
                SUM(btc_amount) as total_btc,
                AVG(btc_price) as avg_buy_price
            FROM transactions
            WHERE status = "completed"
        ''')

        total = cursor.fetchone()
        portfolio_value = self.get_portfolio_value()

        roi = 0
        if total[1] and total[1] > 0:
            roi = ((portfolio_value - total[1]) / total[1]) * 100

        stats = {
            'total_transactions': total[0] or 0,
            'total_invested_usd': total[1] or 0,
            'total_btc': total[2] or 0,
            'avg_buy_price': total[3] or 0,
            'current_portfolio_value': portfolio_value,
            'roi_percent': roi
        }

        return stats

    def print_statistics(self):
        """Print formatted statistics"""
        stats = self.get_statistics()

        print("\n" + "="*50)
        print("📊 DCA BOT STATISTICS")
        print("="*50)
        print(f"Total Transactions: {stats['total_transactions']}")
        print(f"Total Invested: ${stats['total_invested_usd']:.2f}")
        print(f"Total BTC: {stats['total_btc']:.8f}")
        print(f"Average Buy Price: ${stats['avg_buy_price']:.2f}")
        print(f"Current Portfolio: ${stats['current_portfolio_value']:.2f}")
        print(f"ROI: {stats['roi_percent']:.2f}%")
        print("="*50 + "\n")

    def run_once(self):
        """Run bot once (for testing)"""
        logger.info("🚀 Running DCA bot (single execution)")

        success = self.execute_dca_purchase()
        self.update_daily_stats()
        self.print_statistics()

        return success

    def run_continuous(self, interval_hours=24):
        """Run bot continuously"""
        logger.info(f"🚀 Starting DCA bot - Running every {interval_hours} hours")

        while True:
            try:
                self.execute_dca_purchase()
                self.update_daily_stats()
                self.print_statistics()

                # Wait for next execution
                wait_seconds = interval_hours * 3600
                logger.info(f"⏰ Next execution in {interval_hours} hours")
                time.sleep(wait_seconds)

            except KeyboardInterrupt:
                logger.info("🛑 Bot stopped by user")
                break
            except Exception as e:
                logger.error(f"❌ Error in main loop: {e}")
                time.sleep(300)  # Wait 5 minutes before retrying

    def close(self):
        """Close database connection"""
        self.db_conn.close()
        logger.info("✅ Bot closed")


def main():
    """Main entry point"""
    import argparse

    parser = argparse.ArgumentParser(description='30-Day Sovereignty DCA Bot')
    parser.add_argument('--mode', choices=['once', 'continuous'], default='once',
                       help='Run mode: once or continuous')
    parser.add_argument('--interval', type=int, default=24,
                       help='Interval in hours for continuous mode (default: 24)')
    parser.add_argument('--stats', action='store_true',
                       help='Show statistics only')

    args = parser.parse_args()

    bot = DCABot()

    try:
        if args.stats:
            bot.print_statistics()
        elif args.mode == 'once':
            bot.run_once()
        else:
            bot.run_continuous(interval_hours=args.interval)
    finally:
        bot.close()


if __name__ == '__main__':
    main()
