#!/usr/bin/env python3
"""
Enhanced Multi-Cloud Orchestration Portal
Advanced web-based UI with real-time monitoring, metrics, and analytics
"""

import os
import yaml
import json
import sqlite3
from flask import Flask, render_template, request, jsonify, redirect, url_for, send_file
from flask_cors import CORS
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional
import threading
import time
import subprocess

app = Flask(__name__)
CORS(app)

# Configuration
ENVIRONMENTS_FILE = os.path.join(os.path.dirname(__file__), '../../config/environments.yaml')
DEPLOYMENT_LOG_DIR = os.path.join(os.path.dirname(__file__), '../../logs/deployments')
DB_FILE = os.path.join(os.path.dirname(__file__), '../../logs/orchestration.db')
STATIC_DIR = os.path.join(os.path.dirname(__file__), 'static')

os.makedirs(DEPLOYMENT_LOG_DIR, exist_ok=True)
os.makedirs(STATIC_DIR, exist_ok=True)

# Initialize database
def init_db():
    """Initialize SQLite database for deployment history and metrics"""
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    
    # Deployment history table
    c.execute('''
        CREATE TABLE IF NOT EXISTS deployments (
            id TEXT PRIMARY KEY,
            environment TEXT NOT NULL,
            status TEXT NOT NULL,
            started_at TEXT NOT NULL,
            completed_at TEXT,
            triggered_by TEXT,
            strategy TEXT,
            version TEXT,
            logs_path TEXT
        )
    ''')
    
    # Metrics table
    c.execute('''
        CREATE TABLE IF NOT EXISTS metrics (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            environment TEXT NOT NULL,
            metric_name TEXT NOT NULL,
            metric_value REAL NOT NULL,
            timestamp TEXT NOT NULL
        )
    ''')
    
    # Alerts table
    c.execute('''
        CREATE TABLE IF NOT EXISTS alerts (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            environment TEXT NOT NULL,
            severity TEXT NOT NULL,
            message TEXT NOT NULL,
            timestamp TEXT NOT NULL,
            acknowledged BOOLEAN DEFAULT 0
        )
    ''')
    
    # Cost tracking table
    c.execute('''
        CREATE TABLE IF NOT EXISTS costs (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            environment TEXT NOT NULL,
            provider TEXT NOT NULL,
            cost REAL NOT NULL,
            currency TEXT DEFAULT 'USD',
            period_start TEXT NOT NULL,
            period_end TEXT NOT NULL,
            resource_type TEXT
        )
    ''')
    
    conn.commit()
    conn.close()

init_db()


def load_environments() -> List[Dict[str, Any]]:
    """Load environments configuration from YAML file"""
    try:
        with open(ENVIRONMENTS_FILE, 'r') as f:
            config = yaml.safe_load(f)
            return config.get('environments', [])
    except Exception as e:
        print(f"Error loading environments: {e}")
        return []


def get_environment_by_name(name: str) -> Optional[Dict[str, Any]]:
    """Get environment configuration by name"""
    environments = load_environments()
    for env in environments:
        if env.get('name') == name:
            return env
    return None


def get_deployment_status(environment_name: str) -> Dict[str, Any]:
    """Get real deployment status for an environment"""
    # In production, this would query Kubernetes, Terraform state, etc.
    # For now, return enhanced mock data with realistic values
    import random
    
    base_status = {
        'status': random.choice(['deployed', 'deploying', 'healthy', 'degraded']),
        'last_deployed': (datetime.now() - timedelta(hours=random.randint(1, 48))).isoformat(),
        'cluster_health': random.choice(['healthy', 'degraded', 'unhealthy']),
        'node_count': random.randint(1, 10),
        'pods_running': random.randint(5, 50),
        'pods_total': random.randint(10, 60),
        'cpu_usage_percent': round(random.uniform(20, 80), 2),
        'memory_usage_percent': round(random.uniform(30, 85), 2),
        'network_in_mbps': round(random.uniform(10, 1000), 2),
        'network_out_mbps': round(random.uniform(10, 500), 2),
        'uptime_days': random.randint(1, 365),
        'last_health_check': datetime.now().isoformat()
    }
    
    # Query database for deployment history
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    c.execute('''
        SELECT COUNT(*) FROM deployments 
        WHERE environment = ? AND status = 'completed'
    ''', (environment_name,))
    base_status['total_deployments'] = c.fetchone()[0]
    
    c.execute('''
        SELECT started_at FROM deployments 
        WHERE environment = ? 
        ORDER BY started_at DESC LIMIT 1
    ''', (environment_name,))
    result = c.fetchone()
    if result:
        base_status['last_deployment'] = result[0]
    
    conn.close()
    
    return base_status


def get_metrics(environment_name: str, hours: int = 24) -> List[Dict[str, Any]]:
    """Get metrics for an environment over time"""
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    
    since = (datetime.now() - timedelta(hours=hours)).isoformat()
    c.execute('''
        SELECT metric_name, metric_value, timestamp 
        FROM metrics 
        WHERE environment = ? AND timestamp >= ?
        ORDER BY timestamp ASC
    ''', (environment_name, since))
    
    rows = c.fetchall()
    conn.close()
    
    metrics = {}
    for row in rows:
        metric_name, value, timestamp = row
        if metric_name not in metrics:
            metrics[metric_name] = []
        metrics[metric_name].append({
            'value': value,
            'timestamp': timestamp
        })
    
    return metrics


def get_alerts(environment_name: Optional[str] = None, unacknowledged_only: bool = False) -> List[Dict[str, Any]]:
    """Get alerts for environment(s)"""
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    
    if environment_name:
        if unacknowledged_only:
            c.execute('''
                SELECT id, environment, severity, message, timestamp 
                FROM alerts 
                WHERE environment = ? AND acknowledged = 0
                ORDER BY timestamp DESC
            ''', (environment_name,))
        else:
            c.execute('''
                SELECT id, environment, severity, message, timestamp 
                FROM alerts 
                WHERE environment = ?
                ORDER BY timestamp DESC
            ''', (environment_name,))
    else:
        if unacknowledged_only:
            c.execute('''
                SELECT id, environment, severity, message, timestamp 
                FROM alerts 
                WHERE acknowledged = 0
                ORDER BY timestamp DESC
            ''')
        else:
            c.execute('''
                SELECT id, environment, severity, message, timestamp 
                FROM alerts 
                ORDER BY timestamp DESC
            ''')
    
    rows = c.fetchall()
    conn.close()
    
    return [{
        'id': row[0],
        'environment': row[1],
        'severity': row[2],
        'message': row[3],
        'timestamp': row[4]
    } for row in rows]


def get_costs(environment_name: Optional[str] = None, days: int = 30) -> List[Dict[str, Any]]:
    """Get cost data for environment(s)"""
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    
    since = (datetime.now() - timedelta(days=days)).isoformat()
    
    if environment_name:
        c.execute('''
            SELECT environment, provider, cost, currency, period_start, period_end, resource_type
            FROM costs 
            WHERE environment = ? AND period_start >= ?
            ORDER BY period_start DESC
        ''', (environment_name, since))
    else:
        c.execute('''
            SELECT environment, provider, cost, currency, period_start, period_end, resource_type
            FROM costs 
            WHERE period_start >= ?
            ORDER BY period_start DESC
        ''', (since,))
    
    rows = c.fetchall()
    conn.close()
    
    return [{
        'environment': row[0],
        'provider': row[1],
        'cost': row[2],
        'currency': row[3],
        'period_start': row[4],
        'period_end': row[5],
        'resource_type': row[6]
    } for row in rows]


# ============================================
# ROUTES
# ============================================

@app.route('/')
def index():
    """Enhanced main dashboard"""
    environments = load_environments()
    
    # Group by provider
    by_provider = {}
    for env in environments:
        provider = env.get('provider', 'unknown')
        if provider not in by_provider:
            by_provider[provider] = []
        by_provider[provider].append(env)
    
    # Get status for each environment
    env_statuses = {}
    for env in environments:
        if env.get('enabled'):
            env_statuses[env['name']] = get_deployment_status(env['name'])
    
    # Get alerts
    alerts = get_alerts(unacknowledged_only=True)
    
    # Get recent deployments
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    c.execute('''
        SELECT id, environment, status, started_at, strategy 
        FROM deployments 
        ORDER BY started_at DESC 
        LIMIT 10
    ''')
    recent_deployments = [{
        'id': row[0],
        'environment': row[1],
        'status': row[2],
        'started_at': row[3],
        'strategy': row[4]
    } for row in c.fetchall()]
    conn.close()
    
    # Calculate totals
    total_environments = len(environments)
    enabled_count = len([e for e in environments if e.get('enabled')])
    total_providers = len(by_provider)
    
    return render_template('dashboard.html',
                         environments=environments,
                         by_provider=by_provider,
                         env_statuses=env_statuses,
                         alerts=alerts,
                         recent_deployments=recent_deployments,
                         total_environments=total_environments,
                         enabled_count=enabled_count,
                         total_providers=total_providers)


@app.route('/api/environments')
def api_environments():
    """API endpoint for environments"""
    environments = load_environments()
    return jsonify(environments)


@app.route('/api/environments/<name>')
def api_environment(name: str):
    """API endpoint for a specific environment"""
    env = get_environment_by_name(name)
    if not env:
        return jsonify({'error': 'Environment not found'}), 404
    
    status = get_deployment_status(name)
    metrics = get_metrics(name, hours=24)
    alerts = get_alerts(name, unacknowledged_only=True)
    costs = get_costs(name, days=30)
    
    return jsonify({
        'config': env,
        'status': status,
        'metrics': metrics,
        'alerts': alerts,
        'costs': costs
    })


@app.route('/api/environments/<name>/deploy', methods=['POST'])
def api_deploy(name: str):
    """Deploy to a specific environment"""
    env = get_environment_by_name(name)
    if not env:
        return jsonify({'error': 'Environment not found'}), 404
    
    if not env.get('enabled'):
        return jsonify({'error': 'Environment is disabled'}), 400
    
    data = request.get_json() or {}
    strategy = data.get('strategy', 'blue-green')
    version = data.get('version', 'latest')
    
    # Create deployment record
    deployment_id = f"{name}-{datetime.now().strftime('%Y%m%d%H%M%S')}"
    log_file = os.path.join(DEPLOYMENT_LOG_DIR, f"{deployment_id}.log")
    
    # Log deployment request
    with open(log_file, 'w') as f:
        f.write(f"Deployment requested for {name} at {datetime.now().isoformat()}\n")
        f.write(f"Strategy: {strategy}\n")
        f.write(f"Version: {version}\n")
        f.write(f"Environment config: {json.dumps(env, indent=2)}\n")
    
    # Store in database
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    c.execute('''
        INSERT INTO deployments (id, environment, status, started_at, triggered_by, strategy, version, logs_path)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    ''', (deployment_id, name, 'queued', datetime.now().isoformat(), 
          data.get('triggered_by', 'api'), strategy, version, log_file))
    conn.commit()
    conn.close()
    
    # In production, trigger actual deployment here
    # subprocess.Popen(['./scripts/deploy.sh', name, strategy, version])
    
    return jsonify({
        'deployment_id': deployment_id,
        'status': 'queued',
        'environment': name,
        'strategy': strategy,
        'version': version,
        'message': 'Deployment queued successfully'
    })


@app.route('/api/environments/<name>/status')
def api_status(name: str):
    """Get deployment status for an environment"""
    status = get_deployment_status(name)
    return jsonify(status)


@app.route('/api/environments/<name>/metrics')
def api_metrics(name: str):
    """Get metrics for an environment"""
    hours = request.args.get('hours', 24, type=int)
    metrics = get_metrics(name, hours=hours)
    return jsonify(metrics)


@app.route('/api/environments/<name>/alerts')
def api_alerts(name: str):
    """Get alerts for an environment"""
    unacknowledged_only = request.args.get('unacknowledged_only', 'false').lower() == 'true'
    alerts = get_alerts(name, unacknowledged_only=unacknowledged_only)
    return jsonify(alerts)


@app.route('/api/alerts/<int:alert_id>/acknowledge', methods=['POST'])
def api_acknowledge_alert(alert_id: int):
    """Acknowledge an alert"""
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    c.execute('UPDATE alerts SET acknowledged = 1 WHERE id = ?', (alert_id,))
    conn.commit()
    conn.close()
    return jsonify({'message': 'Alert acknowledged'})


@app.route('/api/costs')
def api_costs():
    """Get cost data"""
    environment = request.args.get('environment')
    days = request.args.get('days', 30, type=int)
    costs = get_costs(environment, days=days)
    return jsonify(costs)


@app.route('/api/deployments')
def api_deployments():
    """List all deployments with filters"""
    environment = request.args.get('environment')
    status = request.args.get('status')
    limit = request.args.get('limit', 50, type=int)
    
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    
    query = 'SELECT id, environment, status, started_at, completed_at, strategy, version FROM deployments WHERE 1=1'
    params = []
    
    if environment:
        query += ' AND environment = ?'
        params.append(environment)
    
    if status:
        query += ' AND status = ?'
        params.append(status)
    
    query += ' ORDER BY started_at DESC LIMIT ?'
    params.append(limit)
    
    c.execute(query, params)
    rows = c.fetchall()
    conn.close()
    
    deployments = [{
        'id': row[0],
        'environment': row[1],
        'status': row[2],
        'started_at': row[3],
        'completed_at': row[4],
        'strategy': row[5],
        'version': row[6]
    } for row in rows]
    
    return jsonify(deployments)


@app.route('/api/deployments/<deployment_id>/logs')
def api_deployment_logs(deployment_id: str):
    """Get deployment logs"""
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    c.execute('SELECT logs_path FROM deployments WHERE id = ?', (deployment_id,))
    result = c.fetchone()
    conn.close()
    
    if not result or not os.path.exists(result[0]):
        return jsonify({'error': 'Logs not found'}), 404
    
    with open(result[0], 'r') as f:
        logs = f.read()
    
    return jsonify({'logs': logs})


@app.route('/environment/<name>')
def environment_detail(name: str):
    """Enhanced environment detail page"""
    env = get_environment_by_name(name)
    if not env:
        return "Environment not found", 404
    
    status = get_deployment_status(name)
    metrics = get_metrics(name, hours=168)  # 7 days
    alerts = get_alerts(name)
    costs = get_costs(name, days=30)
    
    # Get deployment history
    conn = sqlite3.connect(DB_FILE)
    c = conn.cursor()
    c.execute('''
        SELECT id, status, started_at, completed_at, strategy, version 
        FROM deployments 
        WHERE environment = ? 
        ORDER BY started_at DESC 
        LIMIT 20
    ''', (name,))
    deployments = [{
        'id': row[0],
        'status': row[1],
        'started_at': row[2],
        'completed_at': row[3],
        'strategy': row[4],
        'version': row[5]
    } for row in c.fetchall()]
    conn.close()
    
    return render_template('environment_detail.html',
                         environment=env,
                         status=status,
                         metrics=metrics,
                         alerts=alerts,
                         costs=costs,
                         deployments=deployments)


@app.route('/dashboard/health')
def health_dashboard():
    """Health dashboard comparing all environments"""
    environments = load_environments()
    health_data = []
    
    for env in environments:
        if env.get('enabled'):
            status = get_deployment_status(env['name'])
            health_data.append({
                'name': env['name'],
                'provider': env.get('provider'),
                'region': env.get('region'),
                'status': status,
                'health': status.get('cluster_health', 'unknown')
            })
    
    return render_template('health_dashboard.html', health_data=health_data)


@app.route('/dashboard/costs')
def cost_dashboard():
    """Cost dashboard"""
    costs = get_costs(days=90)
    
    # Aggregate by provider
    by_provider = {}
    total_cost = 0
    
    for cost in costs:
        provider = cost['provider']
        if provider not in by_provider:
            by_provider[provider] = 0
        by_provider[provider] += cost['cost']
        total_cost += cost['cost']
    
    return render_template('cost_dashboard.html',
                         costs=costs,
                         by_provider=by_provider,
                         total_cost=total_cost)


if __name__ == '__main__':
    # Seed some sample data for demonstration
    def seed_sample_data():
        """Seed sample metrics, alerts, and costs for demo"""
        import random
        conn = sqlite3.connect(DB_FILE)
        c = conn.cursor()
        
        # Check if data already exists
        c.execute('SELECT COUNT(*) FROM metrics')
        if c.fetchone()[0] > 0:
            conn.close()
            return
        
        environments = load_environments()
        for env in environments[:3]:  # Seed first 3 environments
            env_name = env['name']
            
            # Generate sample metrics
            for i in range(24):  # 24 hours of data
                timestamp = (datetime.now() - timedelta(hours=24-i)).isoformat()
                c.execute('''
                    INSERT INTO metrics (environment, metric_name, metric_value, timestamp)
                    VALUES (?, ?, ?, ?)
                ''', (env_name, 'cpu_usage', random.uniform(20, 80), timestamp))
                c.execute('''
                    INSERT INTO metrics (environment, metric_name, metric_value, timestamp)
                    VALUES (?, ?, ?, ?)
                ''', (env_name, 'memory_usage', random.uniform(30, 85), timestamp))
            
            # Generate sample alerts
            if random.random() > 0.7:  # 30% chance of alert
                c.execute('''
                    INSERT INTO alerts (environment, severity, message, timestamp)
                    VALUES (?, ?, ?, ?)
                ''', (env_name, random.choice(['warning', 'error']), 
                      f'Sample alert for {env_name}', datetime.now().isoformat()))
            
            # Generate sample costs
            for i in range(30):  # 30 days
                period_start = (datetime.now() - timedelta(days=30-i)).isoformat()
                period_end = (datetime.now() - timedelta(days=29-i)).isoformat()
                c.execute('''
                    INSERT INTO costs (environment, provider, cost, period_start, period_end, resource_type)
                    VALUES (?, ?, ?, ?, ?, ?)
                ''', (env_name, env.get('provider', 'azure'), 
                      random.uniform(10, 500), period_start, period_end, 'compute'))
        
        conn.commit()
        conn.close()
    
    seed_sample_data()
    
    print("🚀 Enhanced Multi-Cloud Orchestration Portal starting...")
    print("📊 Access dashboard at: http://localhost:5000")
    print("🔍 Health dashboard at: http://localhost:5000/dashboard/health")
    print("💰 Cost dashboard at: http://localhost:5000/dashboard/costs")
    
    app.run(debug=True, host='0.0.0.0', port=5000)

