#!/usr/bin/env python3
"""
KAGGLE AGENT - Sistema Autonomo per Competizioni
================================================

Questo agente:
1. Analizza competizioni e sceglie le migliori opportunità
2. Studia i notebook vincenti e le tecniche top
3. Costruisce modelli ottimizzati
4. Sottomette e monitora i risultati
5. Itera per migliorare il ranking

Autore: vincenzorubino
"""

import os
import sys
import json
import subprocess
from datetime import datetime, timedelta
from pathlib import Path

# Configurazione
KAGGLE_USERNAME = "vincenzorubino"
KAGGLE_TOKEN = "KGAT_640efdd03a8156e5a8530f3c47106323"
KAGGLE_ENV = "/var/www/html/bestrading.cuttalo.com/scripts/kaggle-env/bin/kaggle"
BASE_PATH = "/var/www/html/gpu-tools/kaggle"

os.environ['KAGGLE_API_TOKEN'] = KAGGLE_TOKEN


class KaggleAgent:
    """Agente autonomo per competizioni Kaggle"""

    def __init__(self):
        self.competitions = []
        self.my_submissions = {}
        self.best_notebooks = {}
        self.current_competition = None

    def run_kaggle(self, *args):
        """Esegue comando Kaggle API"""
        cmd = [KAGGLE_ENV] + list(args)
        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.stdout, result.stderr, result.returncode

    # =========================================================================
    # ANALISI COMPETIZIONI
    # =========================================================================

    def list_competitions(self, category='all'):
        """Lista competizioni attive"""
        print("\n📊 Analizzando competizioni attive...")
        stdout, stderr, code = self.run_kaggle(
            'competitions', 'list', '-v'
        )
        if code == 0:
            print(stdout)
            return stdout
        return None

    def analyze_competition(self, competition_slug):
        """Analizza una competizione specifica"""
        print(f"\n🔍 Analizzando: {competition_slug}")

        info = {
            'slug': competition_slug,
            'leaderboard': [],
            'top_notebooks': [],
            'my_submissions': []
        }

        # Leaderboard
        stdout, _, _ = self.run_kaggle(
            'competitions', 'leaderboard', '-c', competition_slug, '--show'
        )
        if stdout:
            lines = stdout.strip().split('\n')
            info['leaderboard'] = lines[:20]  # Top 20
            print(f"  Top score: {lines[2].split()[-1] if len(lines) > 2 else 'N/A'}")

        # Top notebooks
        stdout, _, _ = self.run_kaggle(
            'kernels', 'list', '--competition', competition_slug,
            '--sort-by', 'voteCount', '--page-size', '10'
        )
        if stdout:
            info['top_notebooks'] = stdout.strip().split('\n')[:10]
            print(f"  Found {len(info['top_notebooks'])} top notebooks")

        self.current_competition = info
        return info

    # =========================================================================
    # STUDIO NOTEBOOK VINCENTI
    # =========================================================================

    def study_winning_notebooks(self, competition_slug, max_notebooks=5):
        """Scarica e analizza i notebook vincenti"""
        print(f"\n📚 Studiando notebook vincenti per {competition_slug}...")

        # Lista top notebooks
        stdout, _, _ = self.run_kaggle(
            'kernels', 'list', '--competition', competition_slug,
            '--sort-by', 'voteCount', '--page-size', str(max_notebooks)
        )

        if not stdout:
            print("  Nessun notebook trovato")
            return []

        notebooks = []
        lines = stdout.strip().split('\n')[1:]  # Skip header

        for line in lines[:max_notebooks]:
            parts = line.split()
            if len(parts) >= 1:
                kernel_ref = parts[0]
                notebooks.append(kernel_ref)

        # Scarica notebooks
        download_path = f"{BASE_PATH}/{competition_slug}/top-notebooks"
        os.makedirs(download_path, exist_ok=True)

        for nb_ref in notebooks:
            print(f"  Scaricando: {nb_ref}")
            self.run_kaggle('kernels', 'pull', nb_ref, '-p', download_path)

        return notebooks

    def extract_techniques(self, notebook_path):
        """Estrae tecniche chiave da un notebook"""
        techniques = {
            'feature_engineering': [],
            'models': [],
            'preprocessing': [],
            'validation': [],
            'ensemble': []
        }

        try:
            with open(notebook_path) as f:
                if notebook_path.endswith('.ipynb'):
                    nb = json.load(f)
                    code = '\n'.join(
                        ''.join(cell['source'])
                        for cell in nb['cells']
                        if cell['cell_type'] == 'code'
                    )
                else:
                    code = f.read()

            # Rileva tecniche
            if 'LightGBM' in code or 'lgb.' in code:
                techniques['models'].append('LightGBM')
            if 'XGBoost' in code or 'xgb.' in code:
                techniques['models'].append('XGBoost')
            if 'CatBoost' in code or 'cat.' in code:
                techniques['models'].append('CatBoost')
            if 'RandomForest' in code:
                techniques['models'].append('RandomForest')
            if 'neural' in code.lower() or 'keras' in code.lower():
                techniques['models'].append('Neural Network')

            if 'TimeSeriesSplit' in code:
                techniques['validation'].append('TimeSeriesSplit')
            if 'KFold' in code:
                techniques['validation'].append('KFold')

            if '.shift(' in code:
                techniques['feature_engineering'].append('Lag features')
            if '.rolling(' in code:
                techniques['feature_engineering'].append('Rolling statistics')
            if 'ewm(' in code:
                techniques['feature_engineering'].append('Exponential moving avg')

            if 'ensemble' in code.lower() or 'blend' in code.lower():
                techniques['ensemble'].append('Ensemble/Blending')

        except Exception as e:
            print(f"  Errore analisi: {e}")

        return techniques

    # =========================================================================
    # GESTIONE KERNEL E SUBMISSIONS
    # =========================================================================

    def push_kernel(self, kernel_path, metadata_path):
        """Pusha un kernel su Kaggle"""
        print(f"\n🚀 Pushing kernel...")
        stdout, stderr, code = self.run_kaggle(
            'kernels', 'push', '-p', kernel_path
        )
        if code == 0:
            print(f"  ✓ Kernel pushed successfully")
            # Estrai URL
            if 'https://' in stdout:
                url = [l for l in stdout.split() if 'kaggle.com' in l][0]
                print(f"  URL: {url}")
                return url
        else:
            print(f"  ✗ Errore: {stderr}")
        return None

    def check_kernel_status(self, kernel_ref):
        """Controlla stato del kernel"""
        stdout, _, code = self.run_kaggle('kernels', 'status', kernel_ref)
        if code == 0:
            status = stdout.strip().split()[-1].strip('"')
            return status
        return None

    def wait_for_kernel(self, kernel_ref, timeout_minutes=30):
        """Aspetta che un kernel completi"""
        import time
        print(f"\n⏳ Aspettando {kernel_ref}...")
        start = datetime.now()
        max_time = timedelta(minutes=timeout_minutes)

        while datetime.now() - start < max_time:
            status = self.check_kernel_status(kernel_ref)
            print(f"  Status: {status}")

            if status == 'KernelWorkerStatus.COMPLETE':
                print("  ✓ Completato!")
                return True
            elif status == 'KernelWorkerStatus.ERROR':
                print("  ✗ Errore!")
                return False

            time.sleep(60)

        print("  ⚠ Timeout")
        return False

    def download_output(self, kernel_ref, output_path):
        """Scarica output di un kernel"""
        os.makedirs(output_path, exist_ok=True)
        stdout, stderr, code = self.run_kaggle(
            'kernels', 'output', kernel_ref, '-p', output_path
        )
        return code == 0

    def submit(self, competition, submission_file, message):
        """Sottomette a una competizione"""
        print(f"\n📤 Sottomettendo a {competition}...")
        stdout, stderr, code = self.run_kaggle(
            'competitions', 'submit',
            '-c', competition,
            '-f', submission_file,
            '-m', message
        )
        if code == 0:
            print("  ✓ Submission completata!")
            return True
        else:
            print(f"  ✗ Errore: {stderr}")
            return False

    # =========================================================================
    # STRATEGIA AUTOMATICA
    # =========================================================================

    def auto_compete(self, competition_slug):
        """Strategia automatica per una competizione"""
        print("\n" + "="*70)
        print(f"  🤖 KAGGLE AGENT - {competition_slug}")
        print("="*70)

        # 1. Analizza competizione
        info = self.analyze_competition(competition_slug)

        # 2. Studia notebook vincenti
        notebooks = self.study_winning_notebooks(competition_slug)

        # 3. Estrai tecniche
        print("\n📝 Tecniche rilevate:")
        all_techniques = {'models': set(), 'features': set()}

        for nb in notebooks:
            nb_path = f"{BASE_PATH}/{competition_slug}/top-notebooks/{nb.split('/')[-1]}.ipynb"
            if os.path.exists(nb_path):
                tech = self.extract_techniques(nb_path)
                all_techniques['models'].update(tech['models'])
                all_techniques['features'].update(tech['feature_engineering'])

        print(f"  Modelli: {all_techniques['models']}")
        print(f"  Features: {all_techniques['features']}")

        # 4. Report
        report = {
            'competition': competition_slug,
            'timestamp': datetime.now().isoformat(),
            'leaderboard_top': info['leaderboard'][:5],
            'techniques': {k: list(v) for k, v in all_techniques.items()},
            'notebooks_studied': notebooks
        }

        report_path = f"{BASE_PATH}/{competition_slug}/agent-report.json"
        os.makedirs(os.path.dirname(report_path), exist_ok=True)
        with open(report_path, 'w') as f:
            json.dump(report, f, indent=2)

        print(f"\n📄 Report salvato: {report_path}")
        return report

    def get_status(self):
        """Report stato attuale"""
        print("\n" + "="*70)
        print("  KAGGLE AGENT STATUS")
        print("="*70)

        # Lista kernel attivi
        stdout, _, _ = self.run_kaggle('kernels', 'list', '--mine', '--page-size', '10')
        print("\n📋 I tuoi kernel recenti:")
        print(stdout)

        return True


# =============================================================================
# MAIN
# =============================================================================

if __name__ == "__main__":
    agent = KaggleAgent()

    if len(sys.argv) < 2:
        print("""
KAGGLE AGENT - Uso:
  python kaggle-agent.py status              - Mostra stato
  python kaggle-agent.py list                - Lista competizioni
  python kaggle-agent.py analyze <comp>      - Analizza competizione
  python kaggle-agent.py study <comp>        - Studia notebook vincenti
  python kaggle-agent.py auto <comp>         - Strategia automatica completa
  python kaggle-agent.py submit <comp> <file> <msg> - Sottometti
        """)
        sys.exit(0)

    cmd = sys.argv[1]

    if cmd == 'status':
        agent.get_status()

    elif cmd == 'list':
        agent.list_competitions()

    elif cmd == 'analyze' and len(sys.argv) > 2:
        agent.analyze_competition(sys.argv[2])

    elif cmd == 'study' and len(sys.argv) > 2:
        agent.study_winning_notebooks(sys.argv[2])

    elif cmd == 'auto' and len(sys.argv) > 2:
        agent.auto_compete(sys.argv[2])

    elif cmd == 'submit' and len(sys.argv) > 4:
        agent.submit(sys.argv[2], sys.argv[3], sys.argv[4])

    else:
        print("Comando non riconosciuto. Usa 'python kaggle-agent.py' per aiuto.")
