#!/usr/bin/env python3
"""Read-only ExaMark CLI. JSON stdout for coding agents; no credentials in arguments."""
import argparse
import json
import os
import subprocess
import sys
import urllib.error
import urllib.parse
import urllib.request


class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None  # Never forward a library credential to another host.


def configuration(server=None):
    server = (server or os.environ.get('EXAMARK_API_URL') or os.environ.get('MOA_API_URL', '')).rstrip('/')
    parts = urllib.parse.urlsplit(server)
    if not parts.hostname or parts.username or parts.password or parts.query or parts.fragment:
        raise ValueError('Set EXAMARK_API_URL to your HTTPS API origin; no credentials in URLs.')
    if parts.scheme != 'https' and not (parts.scheme == 'http' and parts.hostname in ['127.0.0.1', '::1', 'localhost']):
        raise ValueError('HTTPS is required outside local development.')
    token = os.environ.get('EXAMARK_AGENT_TOKEN') or os.environ.get('MOA_AGENT_TOKEN', '')
    if not token and sys.platform == 'darwin':
        saved = subprocess.run(['security', 'find-generic-password', '-s', 'examark.agent.token', '-w'], capture_output=True, text=True)
        if saved.returncode == 0:
            token = saved.stdout.strip()
    return server, token


def fetch(server, token, path):
    if not token:
        raise ValueError('Set EXAMARK_AGENT_TOKEN to a read-only key created in ExaMark Settings, or use macOS Keychain service examark.agent.token.')
    request = urllib.request.Request(server + path, headers={'Authorization': 'Bearer ' + token, 'Accept': 'application/json', 'User-Agent': 'ExaMark-CLI/1.0'})
    opener = urllib.request.build_opener(NoRedirect())
    try:
        with opener.open(request, timeout=90) as response:
            return json.loads(response.read())
    except urllib.error.HTTPError as error:
        if error.code == 401:
            raise ValueError('Connection key expired or revoked. Create a new read-only key in ExaMark.') from None
        if error.code == 404:
            raise ValueError('This save is not available to your connection.') from None
        raise ValueError('ExaMark returned HTTP ' + str(error.code) + '. No request was retried.') from None
    except (urllib.error.URLError, TimeoutError, ValueError):
        raise ValueError('Could not read ExaMark. Check the API URL and connection. No request was retried.') from None


def main():
    parser = argparse.ArgumentParser(description='Search saved sources from a coding agent. Read-only JSON output.')
    parser.add_argument('--server', help='Public HTTPS API origin (default: EXAMARK_API_URL)')
    parser.add_argument('--version', action='version', version='ExaMark CLI 1.0')
    commands = parser.add_subparsers(dest='command', required=True)
    query = commands.add_parser('search', help='Search original text, summaries, transcripts and video analysis using keywords + vectors')
    query.add_argument('query')
    query.add_argument('--limit', type=int, default=8, choices=range(1, 51), metavar='1..50')
    detail = commands.add_parser('get', help='Read a source and the sections you need')
    detail.add_argument('id')
    detail.add_argument('--sections', help='Comma-separated: original,transcript,analysis,summary (default: all)')
    commands.add_parser('config', help='Show connection configuration without revealing the key')
    args = parser.parse_args()
    try:
        server, token = configuration(args.server)
        if args.command == 'config':
            value = {'server': server, 'key_available': bool(token), 'access': 'Use a read-only key from the app', 'mcp_url': server + '/mcp'}
        elif args.command == 'search':
            if not 1 <= len(args.query.strip()) <= 500:
                raise ValueError('Search query must contain 1-500 characters.')
            value = fetch(server, token, '/search?' + urllib.parse.urlencode({'q': args.query, 'limit': args.limit}))
        else:
            sections = args.sections.split(',') if args.sections else None
            allowed = {'original', 'transcript', 'analysis', 'summary'}
            if sections and not set(sections).issubset(allowed):
                raise ValueError('Sections must be original,transcript,analysis,summary.')
            value = fetch(server, token, '/items/' + urllib.parse.quote(args.id, safe=''))
            if sections:
                keys = ['id','url','title','platform','kind','created_at','status'] + [{'original':'original_markdown'}.get(k,k) for k in sections]
                value = {k:value[k] for k in keys if k in value}
        print(json.dumps(value, ensure_ascii=False, indent=2))
        return 0
    except ValueError as error:
        print(json.dumps({'error': str(error)}, ensure_ascii=False), file=sys.stderr)
        return 1


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