#!/usr/bin/env python3
"""
LLM Router for Hermes Agent — Friz 🦎
=======================================
Reads model_tier from SKILL.md frontmatter and maps it to provider:model.

Usage:
  python3 llm_router.py                        # List all skills with tiers
  python3 llm_router.py site-assessment         # Show recommendation for one skill
  python3 llm_router.py --json site-assessment  # JSON output for scripting
  python3 llm_router.py --cron                  # Cron-compatible: "tier|provider|model"

Tier definitions:
  0 = No LLM needed (cron no_agent, scripts)
  1 = Cheap/Fast  → Google Gemini 2.0 Flash (OpenRouter ~$0.10/M tok)
  2 = Standard     → DeepSeek V4 Flash (current default ~$0.50/M tok)
  3 = Premium      → Claude Opus 5.8 / Haiku 4 (OpenRouter ~$15/M tok)
"""

import os, sys, json, re
from pathlib import Path

SKILLS_DIR = os.path.expanduser("~/.hermes/skills")

# ─── Tier → Provider/Model mapping ───
TIER_MAP = {
    0: {"provider": "none",     "model": "no-llm-needed",              "cost": "free"},
    1: {"provider": "google",   "model": "gemini-2.0-flash-exp",       "cost": "~$0.10/M tok"},
    2: {"provider": "deepseek", "model": "deepseek-v4-flash",           "cost": "~$0.50/M tok", "current_default": True},
    3: {"provider": "anthropic","model": "claude-opus-5.8",             "cost": "~$15/M tok"},
}

# ─── YAML frontmatter parser ───

def parse_frontmatter(filepath):
    """Extract YAML frontmatter fields from SKILL.md"""
    with open(filepath, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Match between first and second '---'
    m = re.match(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
    if not m:
        return {}
    
    yaml_block = m.group(1)
    fields = {}
    
    # Simple key: value parser (no nested YAML)
    for line in yaml_block.split('\n'):
        line = line.strip()
        # Skip lists, nested objects, comments
        if line.startswith('-') or line.startswith(' ') or line.startswith('#'):
            continue
        if ':' in line:
            # Only take the first key definition, not sub-keys
            key, _, value = line.partition(':')
            key = key.strip()
            value = value.strip().strip('"').strip("'")
            if key and not key.startswith(' '):
                fields[key] = value
    
    return fields


def scan_skills(skills_dir=SKILLS_DIR):
    """Scan all SKILL.md files and return {name: {metadata}}"""
    skills = {}
    skills_path = Path(skills_dir)
    
    for md_file in skills_path.rglob("SKILL.md"):
        fm = parse_frontmatter(str(md_file))
        name = fm.get('name', md_file.parent.name)
        tier_str = fm.get('model_tier', '')
        try:
            tier = int(tier_str) if tier_str else None
        except ValueError:
            tier = None
        
        # Relative path
        rel = md_file.relative_to(skills_path)
        
        skills[name] = {
            'file': str(md_file),
            'rel_path': str(rel.parent),
            'description': fm.get('description', '')[:80],
            'model_tier': tier,
            'model_info': TIER_MAP.get(tier, {'model': 'unknown', 'provider': 'unknown'})
        }
    
    return skills


def format_table(skills):
    """Format as text table"""
    lines = []
    lines.append(f"{'Skill':<35} {'Tier':<6} {'Provider':<15} {'Model':<25} {'Cost':<18}")
    lines.append('─' * 100)
    
    for name, info in sorted(skills.items(), key=lambda x: (x[1].get('model_tier') or 99, x[0])):
        tier = info['model_tier']
        if tier is None:
            lines.append(f"{name:<35} {'--':<6} {'no-tier':<15} {'':<25} {'':<18}")
        else:
            mi = TIER_MAP.get(tier, {})
            default = ' ★' if mi.get('current_default') else ''
            lines.append(f"{name:<35} {tier:<6} {mi.get('provider','?'):<15} {mi.get('model','?'):<25} {mi.get('cost','?'):<18}{default}")
    
    return '\n'.join(lines)


# ─── Main ───

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser(description='LLM Router for Hermes skills')
    parser.add_argument('skill', nargs='?', help='Skill name to check')
    parser.add_argument('--json', action='store_true', help='JSON output')
    parser.add_argument('--cron', action='store_true', help='Cron-compatible output')
    
    args = parser.parse_args()
    skills = scan_skills()
    
    if args.skill:
        # Find by name or by path
        info = skills.get(args.skill)
        if not info:
            # Try partial match
            for name, i in skills.items():
                if args.skill.lower() in name.lower():
                    info = i
                    break
        
        if not info:
            print(f"❌ Skill '{args.skill}' not found in {SKILLS_DIR}")
            sys.exit(1)
        
        tier = info['model_tier']
        if tier is None:
            print(f"⚠ Skill '{args.skill}' has no model_tier set.")
            mi = TIER_MAP.get(2)  # default to tier 2
            print(f"   Falling back to: {mi['provider']}/{mi['model']}")
            result = {'name': args.skill, 'model_tier': None, 'recommended_tier': 2, **mi}
        else:
            mi = TIER_MAP.get(tier, {})
            result = {'name': args.skill, 'model_tier': tier, **mi}
        
        if args.json:
            print(json.dumps(result, indent=2))
        elif args.cron:
            t = result.get('model_tier') or 2
            p = TIER_MAP.get(t, {}).get('provider', 'deepseek')
            m = TIER_MAP.get(t, {}).get('model', 'deepseek-v4-flash')
            print(f"{t}|{p}|{m}")
        else:
            default_note = ' (★ CURRENT DEFAULT)' if result.get('current_default') else ''
            print(f"\n📋 Skill:          {args.skill}")
            print(f"   Description:    {info['description']}")
            print(f"   Path:           {info['rel_path']}")
            print(f"   Model Tier:     {result.get('model_tier', '?')}")
            print(f"   Provider:       {result.get('provider', '?')}")
            print(f"   Model:          {result.get('model', '?')}{default_note}")
            print(f"   Est. Cost:      {result.get('cost', '?')}")
            if result.get('current_default'):
                print(f"\n   ✅ Already using the right model (Tier 2 = DeepSeek V4 Flash)")
            elif (result.get('model_tier') or 0) > 2:
                print(f"\n   💡 RECOMMENDED: Switch to {result.get('model')} for optimal results")
                print(f"      Run: hermes config set model.provider {result.get('provider')}")
                print(f"      And:  hermes config set model.default {result.get('model')}")
    else:
        # List all
        if args.json:
            out = {}
            for name, info in skills.items():
                tier = info['model_tier']
                out[name] = {
                    'model_tier': tier,
                    'path': info['rel_path'],
                    'description': info['description'],
                    **TIER_MAP.get(tier, {})
                }
            print(json.dumps(out, indent=2))
        else:
            print("\n🔌 LLM Router — Skill Model Requirements")
            print("=" * 100)
            print(format_table(skills))
            print(f"\n{'':>88}★ = current default (Tier 2)")
            print(f"\n📊 Total skills with model_tier: {sum(1 for s in skills.values() if s['model_tier'] is not None)}")
            print(f"   Skills without model_tier:    {sum(1 for s in skills.values() if s['model_tier'] is None)}")
            print(f"\n   Usage: python3 {sys.argv[0]} <skill_name>")
