#!/usr/bin/env python3
"""Small Karakeep API helper that reads its token from the local encrypted vault.

Default behavior:
- reads `.secrets/karakeep_secrets.json.enc`
- uses `baseUrl` + `apiKey`
- targets `/api/v1/...` routes unless an absolute path is given

Examples:
  automation/bin/karakeep_api.py bookmarks --pretty
  automation/bin/karakeep_api.py tags --pretty
  automation/bin/karakeep_api.py /api/health --raw-path --pretty
  automation/bin/karakeep_api.py bookmarks --query limit=5 --pretty
"""

from __future__ import annotations

import argparse
import json
import os
import subprocess
import sys
from pathlib import Path
from typing import Any
from urllib import error, parse, request

SCRIPT_DIR = Path(__file__).resolve().parent
REPO_ROOT = SCRIPT_DIR.parent.parent
WORKSPACE = Path('/home/fizzlepoof/.openclaw/workspace')
DEFAULT_SECRETS_DIR = WORKSPACE / '.secrets'
DEFAULT_SECRET_FILE = DEFAULT_SECRETS_DIR / 'karakeep_secrets.json.enc'
DEFAULT_KEY_FILE = DEFAULT_SECRETS_DIR / 'encryption.key'
DEFAULT_TIMEOUT = 30


def decrypt_json(path: Path, key_file: Path) -> dict[str, Any]:
    raw = subprocess.check_output([
        'openssl', 'enc', '-d', '-aes-256-cbc', '-pbkdf2',
        '-in', str(path),
        '-pass', f'file:{key_file}',
    ])
    return json.loads(raw)


def parse_kv(items: list[str]) -> dict[str, str]:
    out: dict[str, str] = {}
    for item in items:
        if '=' not in item:
            raise SystemExit(f'Expected key=value, got: {item}')
        key, value = item.split('=', 1)
        out[key] = value
    return out


def build_url(base_url: str, endpoint: str, raw_path: bool) -> str:
    base = base_url.rstrip('/')
    if raw_path:
        if not endpoint.startswith('/'):
            endpoint = '/' + endpoint
        return base + endpoint
    endpoint = endpoint.strip('/')
    return f'{base}/api/v1/{endpoint}'


def api_request(method: str, url: str, api_key: str, *, query: dict[str, str] | None = None,
                body: dict[str, Any] | list[Any] | None = None, timeout: int = DEFAULT_TIMEOUT) -> tuple[int, Any, dict[str, str]]:
    if query:
        url += ('&' if '?' in url else '?') + parse.urlencode(query, doseq=True)
    data = None
    headers = {
        'Authorization': f'Bearer {api_key}',
        'Accept': 'application/json',
        'User-Agent': 'doris-karakeep-helper/1.0',
    }
    if body is not None:
        data = json.dumps(body).encode('utf-8')
        headers['Content-Type'] = 'application/json'
    req = request.Request(url, data=data, method=method.upper(), headers=headers)
    try:
        with request.urlopen(req, timeout=timeout) as resp:
            raw = resp.read().decode('utf-8', 'replace')
            ctype = resp.headers.get('Content-Type', '')
            payload = json.loads(raw) if 'json' in ctype else raw
            return resp.status, payload, dict(resp.headers.items())
    except error.HTTPError as exc:
        raw = exc.read().decode('utf-8', 'replace')
        try:
            payload = json.loads(raw)
        except Exception:
            payload = raw
        return exc.code, payload, dict(exc.headers.items())


def main() -> int:
    parser = argparse.ArgumentParser(description='Query Karakeep using the encrypted local vault secret.')
    parser.add_argument('endpoint', help='Endpoint alias/path. Default base is /api/v1/. Example: bookmarks, tags, lists')
    parser.add_argument('--method', default='GET', help='HTTP method (default: GET)')
    parser.add_argument('--query', action='append', default=[], metavar='KEY=VALUE', help='Query params')
    parser.add_argument('--data', action='append', default=[], metavar='KEY=VALUE', help='JSON body fields')
    parser.add_argument('--json-body', help='Raw JSON body string')
    parser.add_argument('--raw-path', action='store_true', help='Use endpoint as-is instead of prefixing /api/v1/')
    parser.add_argument('--pretty', action='store_true', help='Pretty-print JSON output')
    parser.add_argument('--headers', action='store_true', help='Print response headers to stderr')
    parser.add_argument('--timeout', type=int, default=DEFAULT_TIMEOUT)
    parser.add_argument('--secret-file', default=str(DEFAULT_SECRET_FILE))
    parser.add_argument('--key-file', default=str(DEFAULT_KEY_FILE))
    args = parser.parse_args()

    secret = decrypt_json(Path(args.secret_file), Path(args.key_file))
    base_url = secret['baseUrl']
    api_key = secret['apiKey']

    query = parse_kv(args.query)
    body: dict[str, Any] | list[Any] | None = None
    if args.json_body:
        body = json.loads(args.json_body)
    elif args.data:
        body = parse_kv(args.data)

    url = build_url(base_url, args.endpoint, args.raw_path)
    status, payload, headers = api_request(args.method, url, api_key, query=query, body=body, timeout=args.timeout)

    if args.headers:
        for k, v in headers.items():
            print(f'{k}: {v}', file=sys.stderr)

    if isinstance(payload, (dict, list)):
        if args.pretty:
            print(json.dumps(payload, indent=2, sort_keys=True))
        else:
            print(json.dumps(payload))
    else:
        print(payload)

    return 0 if 200 <= status < 300 else 1


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