"""ML Health Check — monitor model accuracy & degradation alerts.

Mengecek kesehatan model ML berdasarkan perbandingan prediksi sinyal
vs pergerakan harga aktual. Deteksi degradasi model secara dini.

Health levels:
  🟢 Healthy  — Accuracy >60%, no degradation
  🟡 Warning  — Accuracy 50-60% or declining trend
  🔴 Critical — Accuracy <50% or rapid degradation

Checks performed:
  - Overall signal accuracy (BUY/SELL vs actual price movement)
  - Accuracy per confidence level (High/Medium/Low)
  - Rolling 7-day accuracy trend
  - Feature importance analysis
  - Model file freshness
  - Degradation detection

Usage:
    # Health check crypto models
    python3 scripts/ml_health_check.py

    # Saham IDX, periode 60 hari
    python3 scripts/ml_health_check.py --asset-type stock --period 60

    # Output JSON (untuk monitoring tools)
    python3 scripts/ml_health_check.py --json

    # Quiet — hanya status dan alerts
    python3 scripts/ml_health_check.py --quiet

    # Exit code non-zero jika ada critical alert
    python3 scripts/ml_health_check.py --strict

Cron example:
    # Check setiap 6 jam, alert jika degradasi
    0 */6 * * * cd /path && .venv/bin/python scripts/ml_health_check.py --strict --quiet >> logs/ml_health.log 2>&1
"""
from __future__ import annotations

import argparse
import json as json_module
import os
import sys

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from dotenv import load_dotenv
load_dotenv()


def main():
    parser = argparse.ArgumentParser(
        description='Check ML model health, accuracy & degradation',
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument('--asset-type', default='stock',
                        choices=['crypto', 'stock', 'stock_us'],
                        help='Asset type (default: stock)')
    parser.add_argument('--period', type=int, default=30,
                        help='Evaluation period in days (default: 30)')
    parser.add_argument('--quiet', '-q', action='store_true',
                        help='Quiet — hanya status dan alerts')
    parser.add_argument('--json', action='store_true',
                        help='Output JSON')
    parser.add_argument('--strict', action='store_true',
                        help='Exit code 1 jika ada critical alert')
    args = parser.parse_args()

    from app import create_app
    app = create_app()

    with app.app_context():
        from app.helpers.market_db import switch_market_schema
        switch_market_schema(args.asset_type)

        from app.services.ml_health_monitor import MLHealthMonitor

        monitor = MLHealthMonitor()
        report = monitor.get_health_report(
            asset_type=args.asset_type,
            period_days=args.period,
        )

        if args.json:
            print(json_module.dumps(report, indent=2, default=str))
            _exit_strict(args.strict, report)
            return

        accuracy = report.get('accuracy', {})
        degradation = report.get('degradation', {})
        model_info = report.get('model_info', {})
        feature_imp = report.get('feature_importance', [])

        # ── Header ──
        status = degradation.get('status', 'unknown')
        status_icon = {'healthy': '🟢', 'warning': '🟡', 'critical': '🔴'}.get(status, '⬜')

        print(f'\n{status_icon}  ML Health Report — {args.asset_type} ({args.period}d)')
        print(f'{"═" * 70}')

        # ── Overall Accuracy ──
        overall = accuracy.get('overall_accuracy', 0)
        total_eval = accuracy.get('total_evaluated', 0)
        correct = accuracy.get('correct', 0)

        print(f'\n📊  Signal Accuracy')
        print(f'    Overall    : {overall:.1f}%  ({correct}/{total_eval} correct)')

        buy_acc = accuracy.get('buy_accuracy', 0)
        sell_acc = accuracy.get('sell_accuracy', 0)
        print(f'    BUY signals: {buy_acc:.1f}%')
        print(f'    SELL signals: {sell_acc:.1f}%')

        # Accuracy by confidence
        by_conf = accuracy.get('by_confidence', {})
        if by_conf and not args.quiet:
            print(f'\n    By Confidence:')
            for level in ['High', 'Medium', 'Low']:
                if level in by_conf:
                    c = by_conf[level]
                    acc = c.get('accuracy', 0)
                    cnt = c.get('total', 0)
                    icon = '🟢' if acc >= 60 else ('🟡' if acc >= 50 else '🔴')
                    print(f'      {icon} {level:<8}: {acc:.1f}%  ({cnt} signals)')

        # Rolling 7d
        rolling = accuracy.get('rolling_7d', 0)
        trend = accuracy.get('trend', 0)
        trend_icon = '📈' if trend > 0 else ('📉' if trend < 0 else '➡️')
        print(f'\n    Rolling 7d : {rolling:.1f}%  {trend_icon} trend={trend:+.1f}%')

        # ── Model Info ──
        if not args.quiet:
            print(f'\n🤖  Model Info')
            print(f'    Type      : {model_info.get("model_type", "N/A")}')
            print(f'    Algorithms: {", ".join(model_info.get("algorithms", []))}')
            print(f'    Last train: {model_info.get("last_retrain", "N/A")}')
            model_files = model_info.get('model_files', 0)
            print(f'    Cached    : {model_files} model files')

        # ── Feature Importance ──
        if feature_imp and not args.quiet:
            print(f'\n🔧  Top Features')
            for i, f in enumerate(feature_imp[:10], 1):
                name = f.get('feature', '?')
                imp = f.get('importance', 0)
                bar = '█' * int(imp * 50)
                print(f'    {i:2d}. {name:<25} {imp:.4f}  {bar}')

        # ── Degradation ──
        print(f'\n⚠️   Degradation Status: {status_icon} {status.upper()}')
        needs_retrain = degradation.get('needs_retrain', False)
        if needs_retrain:
            print(f'    🔄  RETRAINING RECOMMENDED')

        alerts = degradation.get('alerts', [])
        if alerts:
            print(f'\n    Alerts:')
            for alert in alerts:
                level = alert.get('level', 'info')
                msg = alert.get('message', '')
                icon = {'critical': '🔴', 'warning': '🟡', 'optimization': '💡'}.get(level, 'ℹ️')
                print(f'      {icon} [{level}] {msg}')
        else:
            print(f'    ✅  No alerts — all clear')

        print(f'\n{"═" * 70}')

        _exit_strict(args.strict, report)


def _exit_strict(strict, report):
    """Exit with code 1 if --strict and critical alerts exist."""
    if not strict:
        return
    degradation = report.get('degradation', {})
    if degradation.get('status') == 'critical':
        sys.exit(1)
    alerts = degradation.get('alerts', [])
    if any(a.get('level') == 'critical' for a in alerts):
        sys.exit(1)


if __name__ == '__main__':
    main()
