#!/usr/bin/env python3
"""
REGENISIS COSMOLOGY — Independent Verification Suite
Test Harness for DeepSeek & Researchers

Runs the public backtest API across all major seismic zones and produces
a consolidated accuracy report with multiple tolerance levels.

Author: Independent Verification
Engine: BRETT v4.2.0 — developed by Nicolas
Usage: python3 regenisis_verification.py [--quick] [--report-only]
"""

import json
import requests
import sqlite3
import pandas as pd
from datetime import datetime, timedelta
from typing import Dict, List, Tuple, Optional
from pathlib import Path
import time
import argparse

# ============================================================
# CONFIGURATION
# ============================================================

BASE_URL = "https://earthpulse.abacusai.app/api/predictions/backtest"
LEDGER_URL = "https://earthpulse.abacusai.app/api/predictions/ledger"

SEISMIC_ZONES = [
    # Ring of Fire
    ("Japan", 35.7, 139.7),
    ("Chile", -33.4, -70.7),
    ("Indonesia", -6.2, 106.8),
    ("California", 34.1, -118.3),
    ("New Zealand", -41.3, 174.8),
    ("Peru", -12.0, -77.0),
    ("Mexico", 19.4, -99.1),
    ("Philippines", 14.6, 120.9),
    ("Kamchatka", 53.0, 158.7),
    ("Alaska", 61.2, -149.9),
    ("Cascadia", 45.0, -123.0),
    ("Taiwan", 23.7, 121.0),
    # Mediterranean-Asian Belt
    ("Turkey", 39.9, 32.9),
    ("Iran", 33.0, 52.0),
    ("Italy", 41.9, 12.5),
    ("Greece", 38.0, 23.7),
    ("Himalayas", 27.9, 85.3),
    ("Pakistan", 30.4, 69.3),
    ("Afghanistan", 34.5, 69.2),
    ("Romania", 45.9, 26.9),
    # Mid-Atlantic Ridge
    ("Iceland", 64.1, -21.9),
    ("Azores", 38.7, -27.2),
    ("St Helena", -16.0, -5.7),
    # Other significant zones
    ("East Africa Rift", -1.9, 36.9),
    ("Red Sea", 19.0, 38.0),
    ("Caribbean", 18.2, -66.5),
    ("Fiji-Tonga", -18.0, -175.0),
    ("Vanuatu", -17.7, 168.3),
    ("Solomon Islands", -9.4, 159.9),
    ("Papua New Guinea", -6.0, 147.0),
    ("Myanmar", 19.7, 96.2),
    ("Caucasus", 41.7, 44.8),
    ("Balkans", 44.0, 20.0),
]

TIME_PERIODS = [
    ("2023-01-01", "2024-01-01", "Full Year 2023"),
    ("2022-01-01", "2023-01-01", "Full Year 2022"),
    ("2021-01-01", "2022-01-01", "Full Year 2021"),
    ("2023-07-01", "2024-07-01", "Recent 12 Months"),
    ("2020-01-01", "2023-01-01", "3-Year Baseline"),
]

REQUEST_DELAY_SECONDS = 0.5
MAX_RETRIES = 3

# ============================================================
# DATABASE
# ============================================================

class VerificationDatabase:
    def __init__(self, db_path: Path = Path("regenisis_verification.db")):
        self.db_path = db_path
        self._init()

    def _init(self):
        conn = sqlite3.connect(self.db_path)
        c = conn.cursor()
        c.execute('''CREATE TABLE IF NOT EXISTS backtest_results (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            zone_name TEXT, latitude REAL, longitude REAL,
            start_date TEXT, end_date TEXT, period_label TEXT,
            total_events_tested INTEGER,
            accuracy_1_5 REAL, accuracy_1_0 REAL, accuracy_0_5 REAL,
            test_timestamp TEXT,
            UNIQUE(zone_name, start_date, end_date)
        )''')
        c.execute('''CREATE TABLE IF NOT EXISTS summary_stats (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            calculation_date TEXT, total_tests INTEGER,
            global_accuracy_1_5 REAL, global_accuracy_1_0 REAL, global_accuracy_0_5 REAL,
            weighted_accuracy_1_5 REAL, best_zone TEXT, worst_zone TEXT,
            total_events_analyzed INTEGER
        )''')
        conn.commit()
        conn.close()

    def insert_result(self, r: Dict):
        conn = sqlite3.connect(self.db_path)
        conn.execute('''INSERT OR REPLACE INTO backtest_results
            (zone_name,latitude,longitude,start_date,end_date,period_label,
             total_events_tested,accuracy_1_5,accuracy_1_0,accuracy_0_5,test_timestamp)
            VALUES (?,?,?,?,?,?,?,?,?,?,?)''',
            (r['zone_name'],r['latitude'],r['longitude'],r['start_date'],r['end_date'],
             r['period_label'],r['total_events_tested'],r['accuracy_1_5'],
             r['accuracy_1_0'],r['accuracy_0_5'],r['test_timestamp']))
        conn.commit(); conn.close()

    def get_all_results(self) -> pd.DataFrame:
        return pd.read_sql_query("SELECT * FROM backtest_results", sqlite3.connect(self.db_path))

# ============================================================
# API CLIENT
# ============================================================

class APIClient:
    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update({'User-Agent': 'REGENISIS-Verification/1.0'})

    def backtest(self, name, lat, lng, start, end) -> Optional[Dict]:
        params = {'lat': lat, 'lng': lng, 'start': start, 'end': end, 'name': name}
        for attempt in range(MAX_RETRIES):
            try:
                r = self.session.get(BASE_URL, params=params, timeout=60)
                r.raise_for_status()
                data = r.json()
                if 'accuracy_tolerance_1_5' in data:
                    return data
                print(f"  Warning: unexpected response for {name}")
                return None
            except Exception as e:
                print(f"  Attempt {attempt+1} failed for {name}: {e}")
                if attempt < MAX_RETRIES - 1:
                    time.sleep(REQUEST_DELAY_SECONDS * 2)
        return None

    def fetch_ledger(self) -> Optional[Dict]:
        try:
            r = self.session.get(LEDGER_URL, timeout=30)
            r.raise_for_status()
            return r.json()
        except Exception as e:
            print(f"Warning: ledger fetch failed: {e}")
            return None

# ============================================================
# ACCURACY CALCULATIONS
# ============================================================

def weighted_accuracy(df: pd.DataFrame) -> float:
    total = df['total_events_tested'].sum()
    if total == 0: return 0.0
    return (df['accuracy_1_5'] * df['total_events_tested']).sum() / total

def baseline_comparison(df: pd.DataFrame) -> Dict:
    BASELINE = 10.0
    actual = df['accuracy_1_5'].mean()
    return {
        'baseline_pct': BASELINE,
        'actual_pct': round(actual, 2),
        'improvement_pct': round(actual - BASELINE, 2),
        'improvement_factor': round(actual / BASELINE, 2) if BASELINE > 0 else 0
    }

def confidence_intervals(df: pd.DataFrame) -> Dict:
    import numpy as np
    from scipy import stats
    acc = df['accuracy_1_5'].dropna().values
    if len(acc) < 2:
        return {'error': 'Insufficient data'}
    mean = np.mean(acc)
    se = np.std(acc, ddof=1) / np.sqrt(len(acc))
    ci = stats.t.interval(0.95, len(acc)-1, loc=mean, scale=se)
    return {'mean': round(mean,2), 'std_error': round(se,2),
            'ci_lower_95': round(ci[0],2), 'ci_upper_95': round(ci[1],2),
            'sample_size': len(acc)}

# ============================================================
# REPORT GENERATOR
# ============================================================

class ReportGenerator:
    def __init__(self, db: VerificationDatabase):
        self.db = db
        self.out = Path("verification_reports")
        self.out.mkdir(exist_ok=True)

    def generate(self) -> Dict:
        df = self.db.get_all_results()
        if df.empty:
            return {"error": "No data. Run tests first."}

        zone_perf = df.groupby('zone_name')['accuracy_1_5'].mean().sort_values(ascending=False)
        zone_details = []
        for z in df['zone_name'].unique():
            zd = df[df['zone_name'] == z]
            zone_details.append({
                'zone': z, 'tests': len(zd),
                'events': int(zd['total_events_tested'].sum()),
                'accuracy_1_5': round(zd['accuracy_1_5'].mean(), 2),
                'accuracy_1_0': round(zd['accuracy_1_0'].mean(), 2),
                'accuracy_0_5': round(zd['accuracy_0_5'].mean(), 2),
            })

        report = {
            'report_timestamp': datetime.utcnow().isoformat(),
            'engine': 'BRETT v4.2.0 — REGENISIS COSMOLOGY',
            'summary': {
                'total_tests': len(df),
                'zones_tested': df['zone_name'].nunique(),
                'total_events': int(df['total_events_tested'].sum()),
                'global_accuracy_1_5': round(df['accuracy_1_5'].mean(), 2),
                'global_accuracy_1_0': round(df['accuracy_1_0'].mean(), 2),
                'global_accuracy_0_5': round(df['accuracy_0_5'].mean(), 2),
                'weighted_accuracy_1_5': round(weighted_accuracy(df), 2),
                'best_zone': f"{zone_perf.index[0]} ({round(zone_perf.iloc[0],2)}%)",
                'worst_zone': f"{zone_perf.index[-1]} ({round(zone_perf.iloc[-1],2)}%)",
            },
            'baseline': baseline_comparison(df),
            'confidence': confidence_intervals(df),
            'zone_performance': zone_details,
        }
        return report

    def save_all(self, report: Dict):
        # JSON
        with open(self.out / "consolidated_report.json", 'w') as f:
            json.dump(report, f, indent=2)
        print(f"  Saved: {self.out}/consolidated_report.json")

        # CSV
        df = self.db.get_all_results()
        if not df.empty:
            df.to_csv(self.out / "all_backtest_results.csv", index=False)
            print(f"  Saved: {self.out}/all_backtest_results.csv")

        # Markdown
        md = self._markdown(report)
        with open(self.out / "verification_report.md", 'w') as f:
            f.write(md)
        print(f"  Saved: {self.out}/verification_report.md")

    def _markdown(self, r: Dict) -> str:
        s = r['summary']
        b = r['baseline']
        c = r['confidence']
        md = f"""# REGENISIS COSMOLOGY — Independent Verification Report

**Generated:** {r['report_timestamp']}
**Engine:** {r['engine']}

## Summary

| Metric | Value |
|--------|-------|
| Total Tests | {s['total_tests']} |
| Zones Tested | {s['zones_tested']} |
| USGS Events Analyzed | {s['total_events']:,} |
| Global Accuracy (±1.5) | {s['global_accuracy_1_5']}% |
| Global Accuracy (±1.0) | {s['global_accuracy_1_0']}% |
| Global Accuracy (±0.5) | {s['global_accuracy_0_5']}% |
| Weighted Accuracy (±1.5) | {s['weighted_accuracy_1_5']}% |
| Best Zone | {s['best_zone']} |
| Worst Zone | {s['worst_zone']} |

## Baseline Comparison

| Metric | Value |
|--------|-------|
| Random Baseline | {b['baseline_pct']}% |
| Engine Accuracy | {b['actual_pct']}% |
| Improvement | {b['improvement_pct']}% |
| Factor | {b['improvement_factor']}x |

## Confidence Intervals (95%)

| Metric | Value |
|--------|-------|
| Mean | {c.get('mean','N/A')}% |
| Std Error | ±{c.get('std_error','N/A')}% |
| 95% CI | [{c.get('ci_lower_95','N/A')}%, {c.get('ci_upper_95','N/A')}%] |
| Sample Size | {c.get('sample_size','N/A')} |

## Per-Zone Performance

| Zone | Tests | Events | ±1.5 | ±1.0 | ±0.5 |
|------|-------|--------|------|------|------|
"""
        for z in r['zone_performance']:
            md += f"| {z['zone']} | {z['tests']} | {z['events']} | {z['accuracy_1_5']}% | {z['accuracy_1_0']}% | {z['accuracy_0_5']}% |\n"

        md += """
## Methodology

- Each prediction uses ONLY prior month's earthquakes as context (no data leakage)
- Accuracy at three tolerance levels: ±0.5, ±1.0, ±1.5 magnitude
- USGS Earthquake Hazards Program is the source of truth
- Complete raw data in SQLite database for independent audit

---
*Generated by the REGENISIS COSMOLOGY Independent Verification Suite*
"""
        return md

# ============================================================
# TEST HARNESS
# ============================================================

class TestHarness:
    def __init__(self):
        self.db = VerificationDatabase()
        self.client = APIClient()
        self.reports = ReportGenerator(self.db)

    def run_backtests(self, limit_zones=None, limit_periods=None):
        zones = SEISMIC_ZONES[:limit_zones] if limit_zones else SEISMIC_ZONES
        periods = TIME_PERIODS[:limit_periods] if limit_periods else TIME_PERIODS
        total = len(zones) * len(periods)
        current = 0

        print(f"\n{'='*60}")
        print(f"REGENISIS COSMOLOGY — Independent Verification Suite")
        print(f"{'='*60}")
        print(f"Tests: {total} | Zones: {len(zones)} | Periods: {len(periods)}")
        print(f"{'='*60}\n")

        for name, lat, lng in zones:
            print(f"📍 {name} ({lat}, {lng})")
            for start, end, label in periods:
                current += 1
                print(f"  [{current}/{total}] {label} ({start} → {end})")
                result = self.client.backtest(name, lat, lng, start, end)
                if result:
                    entry = {
                        'zone_name': name, 'latitude': lat, 'longitude': lng,
                        'start_date': start, 'end_date': end, 'period_label': label,
                        'total_events_tested': result.get('total_events_tested', 0),
                        'accuracy_1_5': result.get('accuracy_tolerance_1_5', 0),
                        'accuracy_1_0': result.get('accuracy_tolerance_1_0', 0),
                        'accuracy_0_5': result.get('accuracy_tolerance_0_5', 0),
                        'test_timestamp': datetime.utcnow().isoformat(),
                    }
                    self.db.insert_result(entry)
                    print(f"    ✓ Events: {entry['total_events_tested']}, Acc: {entry['accuracy_1_5']}% (±1.5)")
                else:
                    print(f"    ✗ Failed")
                time.sleep(REQUEST_DELAY_SECONDS)
            print()

        print(f"\n{'='*60}")
        print(f"✅ Backtesting complete!")
        print(f"{'='*60}\n")

    def fetch_ledger_snapshot(self):
        print("📋 Fetching forward prediction ledger...")
        ledger = self.client.fetch_ledger()
        if ledger:
            stats = ledger.get('statistics', {})
            print(f"  Total: {stats.get('totalPredictions',0)} | Pending: {stats.get('pending',0)} | Confirmed: {stats.get('confirmed',0)} | Refuted: {stats.get('refuted',0)}")
            out = Path("verification_reports")
            out.mkdir(exist_ok=True)
            with open(out / f"ledger_snapshot_{datetime.utcnow().date()}.json", 'w') as f:
                json.dump(ledger, f, indent=2)
        else:
            print("  Warning: could not fetch ledger")

    def generate_reports(self):
        print("\n📊 Generating reports...")
        report = self.reports.generate()
        if 'error' in report:
            print(f"  ✗ {report['error']}")
            return
        self.reports.save_all(report)

        s = report['summary']
        b = report['baseline']
        c = report.get('confidence', {})
        print(f"\n{'='*60}")
        print(f"VERIFICATION SUMMARY")
        print(f"{'='*60}")
        print(f"Global Accuracy (±1.5): {s['global_accuracy_1_5']}%")
        print(f"Global Accuracy (±1.0): {s['global_accuracy_1_0']}%")
        print(f"Global Accuracy (±0.5): {s['global_accuracy_0_5']}%")
        print(f"Weighted Accuracy:      {s['weighted_accuracy_1_5']}%")
        print(f"vs Random Baseline:     +{b['improvement_pct']}%")
        print(f"95% CI:                 ±{c.get('std_error','N/A')}%")
        print(f"{'='*60}")

    def run(self, quick=False):
        if quick:
            print("⚡ QUICK TEST mode (5 zones, 2 periods)")
            self.run_backtests(limit_zones=5, limit_periods=2)
        else:
            self.run_backtests()
        self.fetch_ledger_snapshot()
        self.generate_reports()
        print(f"\n✅ Complete! Outputs: {Path('verification_reports').absolute()}")

# ============================================================
# ENTRY POINT
# ============================================================

def main():
    parser = argparse.ArgumentParser(description='REGENISIS COSMOLOGY Independent Verification Suite')
    parser.add_argument('--quick', action='store_true', help='Quick test (5 zones, 2 periods)')
    parser.add_argument('--zones', type=int, default=None, help='Limit zones')
    parser.add_argument('--periods', type=int, default=None, help='Limit periods')
    parser.add_argument('--report-only', action='store_true', help='Report from existing data')
    args = parser.parse_args()

    harness = TestHarness()
    if args.report_only:
        harness.generate_reports()
        harness.fetch_ledger_snapshot()
    else:
        harness.run(quick=args.quick)

    print("\nUsage:")
    print("  python3 regenisis_verification.py --quick        # Quick test")
    print("  python3 regenisis_verification.py                # Full verification")
    print("  python3 regenisis_verification.py --report-only  # Report only")

if __name__ == "__main__":
    main()
