import json
from pathlib import Path
from datetime import datetime

import pandas as pd
from marco.core.repository import resolve_version

def load_vocab_from_preprocessed(prep_path: Path):
    if not prep_path.exists():
        return set()
    df = pd.read_csv(prep_path, sep='\t', encoding='utf-8')
    tokens = set()
    for t in df['text'].fillna(''):
        tokens.update(t.split())
    return tokens

def compare_versions(v1_ref: str, v2_ref: str, repo_path: Path) -> dict:
    repo_path = Path(repo_path)
    v1 = resolve_version(v1_ref, repo_path)
    v2 = resolve_version(v2_ref, repo_path)
    
    v1_dir = repo_path / '.marco' / 'versions' / v1
    v2_dir = repo_path / '.marco' / 'versions' / v2
    
    m1 = json.loads((v1_dir / 'metrics.json').read_text(encoding='utf-8'))
    m2 = json.loads((v2_dir / 'metrics.json').read_text(encoding='utf-8'))
    
    report = {
        'v1_id': v1,
        'v2_id': v2,
        'v1_ref': v1_ref,
        'v2_ref': v2_ref,
        'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    }
    
    # Metric diffs
    report['metrics'] = {}
    for k in ['n_documents', 'n_tokens', 'vocab_size']:
        a = m1.get(k, 0)
        b = m2.get(k, 0)
        diff = b - a
        pct = f"{(diff / a * 100):.2f}%" if a else "N/A"
        report['metrics'][k] = {'v1': a, 'v2': b, 'diff': diff, 'pct_change': pct}
        
    # Vocab overlap
    t1 = load_vocab_from_preprocessed(v1_dir / 'preprocessed.tsv')
    t2 = load_vocab_from_preprocessed(v2_dir / 'preprocessed.tsv')
    inter = t1 & t2
    union = t1 | t2
    jaccard = len(inter) / len(union) if union else 1.0
    
    report['vocab'] = {
        'v1_size': len(t1), 
        'v2_size': len(t2), 
        'intersection': len(inter), 
        'union': len(union), 
        'jaccard': f"{jaccard:.4f}"
    }
    
    # Configuration difference
    c1 = json.loads((v1_dir / 'config.json').read_text(encoding='utf-8'))
    c2 = json.loads((v2_dir / 'config.json').read_text(encoding='utf-8'))
    report['config_changed'] = c1 != c2
    
    return report

def generate_markdown_report(report: dict, out_dir: Path) -> Path:
    out_dir = Path(out_dir)
    out_dir.mkdir(parents=True, exist_ok=True)
    
    v1_short = report['v1_id'][:8]
    v2_short = report['v2_id'][:8]
    filename = out_dir / f"marco_diff_{v1_short}_vs_{v2_short}.md"
    
    md = [
        f"# Marco Dataset Comparison Report",
        f"**Generated:** {report['timestamp']}\n",
        f"| | Version 1 | Version 2 |",
        f"|---|---|---|",
        f"| **Reference** | `{report['v1_ref']}` | `{report['v2_ref']}` |",
        f"| **Hash ID** | `{v1_short}` | `{v2_short}` |\n",
        f"## 📊 Metrics Difference\n",
        f"| Metric | V1 | V2 | Diff | % Change |",
        f"|---|---|---|---|---|"
    ]
    
    for k, v in report['metrics'].items():
        name = k.replace('_', ' ').title()
        sign = "+" if v['diff'] > 0 else ""
        md.append(f"| **{name}** | {v['v1']} | {v['v2']} | {sign}{v['diff']} | {v['pct_change']} |")
        
    md.append(f"\n## 🔠 Vocabulary Overlap\n")
    vcb = report['vocab']
    md.extend([
        f"- **V1 Unique Terms**: {vcb['v1_size']}",
        f"- **V2 Unique Terms**: {vcb['v2_size']}",
        f"- **Shared Terms (Intersection)**: {vcb['intersection']}",
        f"- **Total Terms (Union)**: {vcb['union']}",
        f"- **Jaccard Similarity**: `{vcb['jaccard']}`\n"
    ])
    
    if report['config_changed']:
        md.append("## ⚠️ Warning: Pipeline Configurations Differ")
        md.append("The DAG preprocessing steps used to generate these two versions are different.")
    else:
        md.append("## ✅ Pipeline Configurations Match")
        md.append("Both versions were generated using the exact same DAG preprocessing steps.")
        
    filename.write_text("\n".join(md), encoding='utf-8')
    return filename
