#!/usr/bin/env python3
"""sdkspindle CLI"""

import argparse
import sys
import os
import glob
from pathlib import Path

from sdkspindle import __version__
from sdkspindle.config import load_config, generate_config

SDK_REF_NAME = "genai_sdk_reference.json"
DEFAULT_MODEL = "gemini-3-flash-preview"


def find_sdk_reference(explicit_path=None):
    if explicit_path and Path(explicit_path).exists():
        return str(explicit_path)
    config = load_config()
    if config and config.get("sdk_reference"):
        p = Path(config["sdk_reference"])
        if p.exists(): return str(p)
    pkg_dir = Path(__file__).parent
    for candidate in [pkg_dir / "data" / SDK_REF_NAME, pkg_dir / SDK_REF_NAME]:
        if candidate.exists(): return str(candidate)
    cwd_ref = Path.cwd() / SDK_REF_NAME
    if cwd_ref.exists(): return str(cwd_ref)
    return None


def resolve_files(file_args, config=None):
    files = []
    if file_args:
        for pattern in file_args:
            expanded = glob.glob(pattern, recursive=True)
            if expanded: files.extend(expanded)
            elif Path(pattern).exists(): files.append(pattern)
    files = [f for f in files if f.endswith((".kt", ".java"))]
    return sorted(set(files))


def cmd_check(args):
    from sdkspindle.check import check_file, load_sdk
    from sdkspindle.fix import apply_fixes
    from sdkspindle.sarif import to_sarif
    config = load_config()
    sdk_path = find_sdk_reference(getattr(args, 'sdk_ref', None))
    if not sdk_path:
        print("ERROR: No SDK reference found.", file=sys.stderr)
        sys.exit(2)
    sdk = load_sdk(sdk_path)
    meta = sdk.get("_meta", {})
    fmt = getattr(args, 'format', 'text')
    if fmt != "sarif":
        print(f"SDK: {meta.get('types', '?')} types, {meta.get('services', '?')} services", file=sys.stderr)
    files = resolve_files(args.files, config)
    if not files:
        print("No files to check.", file=sys.stderr)
        sys.exit(0)
    rule_overrides = (config or {}).get("rules", {})
    all_issues = []
    for filepath in files:
        all_issues.extend(check_file(filepath, sdk, rule_overrides=rule_overrides))
    if getattr(args, 'fix', False):
        fixed = apply_fixes(all_issues, files, sdk)
        if fmt != "sarif": print(f"\n  Auto-fixed {fixed} issue(s).", file=sys.stderr)
        all_issues = []
        for filepath in files:
            all_issues.extend(check_file(filepath, sdk, rule_overrides=rule_overrides))
    if fmt == "sarif":
        import json; print(json.dumps(to_sarif(all_issues), indent=2))
    elif fmt == "json":
        import json; from dataclasses import asdict
        print(json.dumps([asdict(i) for i in all_issues], indent=2))
    else:
        errors, warns = 0, 0
        for issue in sorted(all_issues, key=lambda i: (i.file, i.line)):
            icon = "\u274c" if issue.severity == "ERROR" else "\u26a0\ufe0f "
            loc = f"{issue.file}:{issue.line}" if issue.line > 0 else issue.file
            print(f"  {icon} {loc}  [{issue.code}] {issue.message}")
            if issue.severity == "ERROR": errors += 1
            else: warns += 1
        print(f"\n{'\u2500' * 60}")
        print(f"  {errors} error(s), {warns} warning(s) across {len(files)} file(s)")
    sys.exit(1 if any(i.severity == "ERROR" for i in all_issues) else 0)


def cmd_query(args):
    from sdkspindle.query import query_sdk
    sdk_path = find_sdk_reference(getattr(args, 'sdk_ref', None))
    if not sdk_path:
        print("ERROR: No SDK reference found.", file=sys.stderr)
        sys.exit(2)
    question = " ".join(args.question)
    if not question:
        print("ERROR: Provide a question.", file=sys.stderr)
        sys.exit(2)
    config = load_config()
    model = getattr(args, 'model', None) or (config or {}).get("gemini_model", DEFAULT_MODEL)
    api_key = getattr(args, 'api_key', None) or os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY")
    print(query_sdk(sdk_path, question, model=model, api_key=api_key,
        offline=getattr(args, 'offline', False),
        force_direct=getattr(args, 'direct', False),
        force_proxy=getattr(args, 'proxy', False)))


def cmd_stats(args):
    from sdkspindle.check import load_sdk
    sdk_path = find_sdk_reference(getattr(args, 'sdk_ref', None))
    if not sdk_path:
        print("ERROR: No SDK reference found.", file=sys.stderr)
        sys.exit(2)
    sdk = load_sdk(sdk_path)
    meta = sdk.get("_meta", {})
    types_db = sdk.get("types", {})
    services_db = sdk.get("services", {})
    total_fields = sum(len(t.get("fields", [])) for t in types_db.values())
    total_optional = sum(1 for t in types_db.values() for f in t.get("fields", []) if f.get("optional"))
    total_builder = sum(len(t.get("builderMethods", [])) for t in types_db.values())
    total_varargs = sum(1 for t in types_db.values() for m in t.get("builderMethods", []) if m.get("varargs"))
    total_svc = sum(len(s.get("methods", [])) for s in services_db.values())
    dur = [(t["class"], f["name"]) for t in types_db.values() for f in t.get("fields", []) if "Duration" in f.get("type", "")]
    print(f"\n  sdkspindle SDK Reference Statistics")
    print(f"  {'\u2500' * 44}")
    print(f"  Types: {meta.get('types',0)}  |  Services: {meta.get('services',0)}  |  Other: {meta.get('other',0)}")
    print(f"  Fields: {total_fields} ({total_optional} Optional)  |  Builder methods: {total_builder} ({total_varargs} varargs)")
    print(f"  Service methods: {total_svc}")
    if dur:
        print(f"\n  Duration fields (String/Duration bug traps):")
        for cls, fname in dur: print(f"    {cls}.{fname}")
    print()


def cmd_diff(args):
    import subprocess
    ref = args.ref or "HEAD~1"
    try:
        result = subprocess.run(["git", "diff", "--name-only", "--diff-filter=ACMR", ref],
            capture_output=True, text=True, check=True)
    except (subprocess.CalledProcessError, FileNotFoundError) as e:
        print(f"ERROR: git diff failed: {e}", file=sys.stderr); sys.exit(2)
    changed = [f for f in result.stdout.strip().split("\n") if f.endswith((".kt", ".java"))]
    if not changed:
        print("No Kotlin/Java files changed.", file=sys.stderr); sys.exit(0)
    print(f"Checking {len(changed)} changed file(s)...", file=sys.stderr)
    args.files = changed
    cmd_check(args)


def main():
    parser = argparse.ArgumentParser(prog="sdkspindle",
        description="SDK-aware linter, query engine & auto-fixer for com.google.genai")
    parser.add_argument("--version", action="version", version=f"sdkspindle {__version__}")
    sub = parser.add_subparsers(dest="command")

    p = sub.add_parser("check", help="Lint files against SDK reference")
    p.add_argument("files", nargs="*")
    p.add_argument("--sdk-ref")
    p.add_argument("--fix", action="store_true")
    p.add_argument("--format", choices=["text", "json", "sarif"], default="text")
    p.set_defaults(func=cmd_check)

    p = sub.add_parser("query", help="Natural language SDK lookup")
    p.add_argument("question", nargs="+")
    p.add_argument("--sdk-ref")
    p.add_argument("--model", default=DEFAULT_MODEL)
    p.add_argument("--api-key")
    mg = p.add_mutually_exclusive_group()
    mg.add_argument("--offline", action="store_true")
    mg.add_argument("--direct", action="store_true")
    mg.add_argument("--proxy", action="store_true")
    p.set_defaults(func=cmd_query)

    p = sub.add_parser("stats", help="SDK reference statistics")
    p.add_argument("--sdk-ref")
    p.set_defaults(func=cmd_stats)

    p = sub.add_parser("diff", help="Lint only git-changed files")
    p.add_argument("ref", nargs="?", default="HEAD~1")
    p.add_argument("--sdk-ref")
    p.add_argument("--fix", action="store_true")
    p.add_argument("--format", choices=["text", "json", "sarif"], default="text")
    p.set_defaults(func=cmd_diff)

    p = sub.add_parser("init", help="Generate .sdkspindle.json")
    p.add_argument("--force", action="store_true")
    p.set_defaults(func=lambda a: generate_config(".sdkspindle.json"))

    p = sub.add_parser("extract", help="Extract SDK API surface to JSON")
    p.add_argument("--sdk-zip")
    p.add_argument("--sdk-dir")
    p.add_argument("-o", "--output")
    p.set_defaults(func=lambda a: print("Use: sdkspindle extract --sdk-zip java-genai-main.zip"))

    args = parser.parse_args()
    if not args.command:
        parser.print_help(); sys.exit(0)
    args.func(args)


if __name__ == "__main__":
    main()
