#!/usr/bin/env python3
"""
BMC Recap Parser — Grok 4 Fast
Usage: python3 grok_parse_recap.py "recap text here"
       or pipe: echo "recap..." | python3 grok_parse_recap.py
Returns: JSON array of staged BMC entries
"""

import sys
import json
import os
import subprocess
import re
from datetime import date

# Load xAI API key
def get_api_key():
    # Try env first
    key = os.environ.get("XAI_API_KEY")
    if key:
        return key
    # Try openclaw.json (nested under models.providers.xai)
    try:
        oc_path = os.path.expanduser("~/.openclaw/openclaw.json")
        with open(oc_path) as f:
            cfg = json.load(f)
        providers = cfg.get("models", {}).get("providers", {})
        for name, pdata in providers.items():
            if "x.ai" in pdata.get("baseUrl", ""):
                return pdata.get("apiKey", "")
    except Exception:
        pass
    return None

SYSTEM_PROMPT = """You are a BMC time tracking parser for Adner Cruz, IT Director at BINC (Bertelsmann Inc.).

Your job: parse a free-text daily activity recap into structured 0.5-hour time blocks for the BMC chargeback spreadsheet.

VALID IT_Operations TaskNames (ONLY use these exact strings):
- IT1
- HR
- Other IT
- Other department
- Admin/miscellaneous
- PTO

VALID Entities (select best match from this list):
- BINC internal
- *Across all entities
- *For Germany
- Bertelsmann Digital Health
- Bertelsmann Digital Health Inc
- Penguin Random House LLC
- Arvato Systems GmbH
- Arvato Systems North America, Inc.
- Extedo Inc
- Versidi
- Coral Graphics
- Relias Learning
- Education OH
- Other entity
(use "BINC internal" for BINC-specific internal IT work; use "*Across all entities" for cross-entity/shared infrastructure)

RULES:
1. Hours must be in 0.5 increments only (0.5, 1.0, 1.5, 2.0, etc.)
2. Round to nearest 0.5 — never use 0.25 or other fractions
3. Comments must be enterprise-level, governance-framed, one line
4. Total hours must not exceed 8.0 per day (flag if over)
5. Use IT1 for specific IT tasks (setup, config, access, onboarding, infrastructure work)
6. Use Other IT for coordination, documentation, operational overhead
7. Use HR for people-related tasks (offboarding, onboarding coordination with HR)
8. Use Admin/miscellaneous for admin overhead, meetings without clear IT deliverable
9. If entity is unclear, set entity to "FLAG: <reason>" — do not guess
10. If a task is ambiguous, include it but add a flag note

OUTPUT FORMAT (JSON only, no prose):
{
  "date": "M/D/YY",
  "entries": [
    {
      "task_num": 1,
      "task_name": "IT1",
      "entity": "BINC internal",
      "hours": 1.5,
      "comment": "End user device remediation — workstation configuration and identity provisioning",
      "flag": null
    }
  ],
  "total_hours": 4.0,
  "flags": []
}
"""

def parse_recap(recap_text, entry_date=None):
    api_key = get_api_key()
    if not api_key:
        print("ERROR: XAI_API_KEY not found", file=sys.stderr)
        sys.exit(1)

    if entry_date is None:
        entry_date = date.today().strftime("%-m/%-d/%y")

    prompt = f"Today's date: {entry_date}\n\nRecap:\n{recap_text}"

    import http.client

    payload = json.dumps({
        "model": "grok-4-1-fast-non-reasoning",
        "messages": [
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": prompt}
        ],
        "temperature": 0.1,
        "max_tokens": 2000
    }).encode()

    try:
        conn = http.client.HTTPSConnection("api.x.ai", timeout=30)
        conn.request("POST", "/v1/chat/completions", body=payload, headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        })
        resp = conn.getresponse()
        if resp.status != 200:
            print(f"ERROR: API call failed: {resp.status} {resp.reason}", file=sys.stderr)
            sys.exit(1)
        result = json.loads(resp.read())
        content = result["choices"][0]["message"]["content"].strip()
        # Extract JSON from response
        match = re.search(r'\{.*\}', content, re.DOTALL)
        if match:
            return json.loads(match.group())
        else:
            print(f"ERROR: Could not parse JSON from response:\n{content}", file=sys.stderr)
            sys.exit(1)
    except Exception as e:
        print(f"ERROR: {e}", file=sys.stderr)
        sys.exit(1)


def format_staged(parsed):
    """Format staged entries in the standard BMC staging format."""
    lines = [f"📋 BMC Time Entry — {parsed['date']}", ""]
    for e in parsed["entries"]:
        flag = f" ⚠️ {e['flag']}" if e.get("flag") else ""
        lines.append(f"{e['task_num']}. {e['task_name']} | {e['entity']} | {e['hours']}hr | {e['comment']}{flag}")
    lines.append("")
    lines.append(f"Total: {parsed['total_hours']} hours")
    if parsed.get("flags"):
        lines.append(f"⚠️ Flags: {'; '.join(parsed['flags'])}")
    lines.append("")
    lines.append("Confirm to log? ✅")
    return "\n".join(lines)


if __name__ == "__main__":
    if len(sys.argv) > 1:
        recap = " ".join(sys.argv[1:])
    elif not sys.stdin.isatty():
        recap = sys.stdin.read().strip()
    else:
        print("Usage: python3 grok_parse_recap.py \"recap text\"", file=sys.stderr)
        sys.exit(1)

    # Optional date override: --date 3/12/26
    entry_date = None
    if "--date" in sys.argv:
        idx = sys.argv.index("--date")
        if idx + 1 < len(sys.argv):
            entry_date = sys.argv[idx + 1]
            recap = recap.replace(f"--date {entry_date}", "").strip()

    parsed = parse_recap(recap, entry_date)

    # Output both raw JSON and formatted staging
    print("=== PARSED JSON ===")
    print(json.dumps(parsed, indent=2))
    print()
    print("=== STAGED FOR CONFIRMATION ===")
    print(format_staged(parsed))
