#!/usr/bin/env python3
"""Small helper for Kakao OAuth setup.

This does not store credentials. It prints an authorization URL or exchanges
the returned code for tokens.
"""

from __future__ import annotations

import argparse
import getpass
import json
import subprocess
import urllib.parse
import urllib.request
from urllib.error import HTTPError


AUTH_URL = "https://kauth.kakao.com/oauth/authorize"
TOKEN_URL = "https://kauth.kakao.com/oauth/token"
KEYCHAIN_SERVICE = "codex-us-equity-kakao"


def print_auth_url(rest_api_key: str, redirect_uri: str) -> None:
    query = urllib.parse.urlencode(
        {
            "response_type": "code",
            "client_id": rest_api_key,
            "redirect_uri": redirect_uri,
            "scope": "talk_message",
        }
    )
    print(f"{AUTH_URL}?{query}")


def set_keychain_secret(account: str, value: str) -> None:
    subprocess.run(
        ["security", "delete-generic-password", "-s", KEYCHAIN_SERVICE, "-a", account],
        check=False,
        capture_output=True,
        text=True,
    )
    result = subprocess.run(
        [
            "security",
            "add-generic-password",
            "-U",
            "-s",
            KEYCHAIN_SERVICE,
            "-a",
            account,
            "-w",
            value,
        ],
        check=False,
        capture_output=True,
        text=True,
    )
    if result.returncode != 0:
        raise SystemExit(result.stderr.strip() or f"Failed to store {account} in Keychain.")


def exchange_code(
    rest_api_key: str,
    redirect_uri: str,
    code: str,
    client_secret: str | None,
    store_keychain: bool,
) -> None:
    payload = {
        "grant_type": "authorization_code",
        "client_id": rest_api_key,
        "redirect_uri": redirect_uri,
        "code": code,
    }
    if client_secret:
        payload["client_secret"] = client_secret

    encoded = urllib.parse.urlencode(payload).encode("utf-8")
    req = urllib.request.Request(TOKEN_URL, data=encoded, method="POST")
    req.add_header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
    try:
        with urllib.request.urlopen(req, timeout=20) as response:
            result = json.loads(response.read().decode("utf-8"))
    except HTTPError as exc:
        body = exc.read().decode("utf-8", errors="replace")
        raise SystemExit(f"Kakao token exchange failed: HTTP {exc.code} {body}")
    if store_keychain:
        set_keychain_secret("KAKAO_REST_API_KEY", rest_api_key)
        if "refresh_token" in result:
            set_keychain_secret("KAKAO_REFRESH_TOKEN", result["refresh_token"])
        if client_secret:
            set_keychain_secret("KAKAO_CLIENT_SECRET", client_secret)
        print("Stored Kakao credentials in macOS Keychain.")
        print(f"received: {', '.join(sorted(result.keys()))}")
    else:
        print(json.dumps(result, ensure_ascii=False, indent=2))


def main() -> int:
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers(dest="command", required=True)

    auth = subparsers.add_parser("auth-url")
    auth.add_argument("--rest-api-key", required=True)
    auth.add_argument("--redirect-uri", required=True)

    token = subparsers.add_parser("exchange-code")
    token.add_argument("--rest-api-key", required=True)
    token.add_argument("--redirect-uri", required=True)
    token.add_argument("--code", help="Authorization code. If omitted, prompted without echo.")
    token.add_argument("--client-secret")
    token.add_argument("--store-keychain", action="store_true")

    args = parser.parse_args()
    if args.command == "auth-url":
        print_auth_url(args.rest_api_key, args.redirect_uri)
    elif args.command == "exchange-code":
        if not args.code:
            args.code = getpass.getpass("Kakao authorization code: ").strip()
        exchange_code(args.rest_api_key, args.redirect_uri, args.code, args.client_secret, args.store_keychain)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
