import os, sys, subprocess

# Truncate diff to keep token costs low. A full diff of a large repo commit
# can easily hit 10k+ tokens. 6000 chars ≈ ~1500 tokens, enough context for
# a good commit message while keeping per-call cost under ~$0.002 on Haiku.
MAX_DIFF_CHARS = 6000

def _build_prompt(diff: str) -> str:
    if len(diff) > MAX_DIFF_CHARS:
        diff = diff[:MAX_DIFF_CHARS] + "\n... (diff truncated for brevity)"
    return (
        "Write a git commit message for these changes. "
        "Follow this exact format:\n"
        "<Short Summary under 50 chars>\n\n"
        "- Change 1\n"
        "- Change 2\n\n"
        "Rules:\n"
        "1. Use hyphens (-) for bullets. Do NOT use numbers.\n"
        "2. Do not put blank lines between list items.\n"
        f"Return ONLY the message text.\n\nChanges:\n{diff}"
    )

def _try_claude(prompt: str) -> str | None:
    """Claude Haiku — cheap, fast, runs in the cloud."""
    try:
        import anthropic
        print("🤖 Analyzing changes with Claude Haiku...")
        client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
        response = client.messages.create(
            model="claude-haiku-4-5",
            max_tokens=256,
            messages=[{"role": "user", "content": prompt}],
        )
        text = response.content[0].text.strip().replace('"', '')
        return text if text else None
    except Exception as e:
        print(f"   >> Claude failed: {e}")
        return None

def _try_gemini(prompt: str) -> str | None:
    """Gemini 2.0 Flash — second cloud fallback."""
    try:
        from google import genai
        print("🤖 Falling back to Gemini 2.0 Flash...")
        client = genai.Client(api_key=os.getenv("GOOGLE_API_KEY"))
        response = client.models.generate_content(model="gemini-2.0-flash", contents=prompt)
        text = response.text.strip().replace('"', '')
        return text if text else None
    except Exception as e:
        msg = str(e)[:120] + ("..." if len(str(e)) > 120 else "")
        print(f"   >> Gemini failed: {msg}")
        return None

def _try_ollama(prompt: str) -> str | None:
    """Local Ollama — final fallback (privacy, no API key needed)."""
    try:
        print("🤖 Falling back to Local Ollama (qwen2.5-coder:14b)...")
        result = subprocess.run(
            ["ollama", "run", "qwen2.5-coder:14b"],
            input=prompt, capture_output=True, text=True, encoding='utf-8'
        )
        if result.returncode == 0:
            text = result.stdout.strip().replace('"', '')
            return text if text else None
    except Exception as e:
        print(f"   >> Ollama failed: {e}")
    return None

def run():
    try:
        # 1. Stage everything
        subprocess.run(["git", "add", "."], check=True)

        # 2. Get the diff
        diff = subprocess.check_output(["git", "diff", "--cached"]).decode()
        if not diff:
            print("✨ No changes to commit (working tree clean).")
            return

        prompt = _build_prompt(diff)

        # 3. Try LLMs in order: Claude → Gemini → Ollama
        msg = _try_claude(prompt) or _try_gemini(prompt) or _try_ollama(prompt)

        if not msg:
            print("\n❌ All AI backends failed. Aborting.")
            return

        # 4. Confirmation step
        print("\n" + "="*40)
        print("PROPOSED COMMIT MESSAGE:")
        print(f'"{msg}"')
        print("="*40)

        choice = input("\nDo you want to (y)es, (e)dit, or (n)o? ").lower()

        if choice == 'y':
            subprocess.run(["git", "commit", "-m", msg], check=True)
            subprocess.run(["git", "push"], check=True)
            print("\n🚀 Successfully pushed to GitHub!")
        elif choice == 'e':
            subprocess.run(["git", "commit", "-e", "-m", msg], check=True)
            subprocess.run(["git", "push"], check=True)
            print("\n🚀 Successfully pushed after edit!")
        else:
            print("\n❌ Commit aborted. Nothing was pushed.")

    except Exception as e:
        print(f"\nInternal Error: {e}")

if __name__ == "__main__":
    run()
