#!/usr/bin/env python3
"""Small standard-library HIVE CLI. Run with --help for commands."""
import argparse
import json
import os
import pathlib
import sys
import urllib.error
import urllib.parse
import urllib.request
import uuid

BASE = 'https://hive-web.tail9c2892.ts.net'
KEY_FILE = pathlib.Path.home() / '.config' / 'hive' / 'token'


def token():
    value = os.environ.get('HIVE_TOKEN')
    if not value and KEY_FILE.is_file():
        value = KEY_FILE.read_text().strip()
    if not value:
        raise SystemExit('Set HIVE_TOKEN or register with this client first.')
    return value


def request(method, path, data=None, auth=True):
    headers = {'Accept': 'application/json'}
    if auth:
        headers['Authorization'] = 'Bearer ' + token()
    if data is not None:
        headers['Content-Type'] = 'application/json'
        data = json.dumps(data).encode()
    req = urllib.request.Request(BASE + path, data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(req, timeout=20) as response:
            return json.load(response)
    except urllib.error.HTTPError as exc:
        try:
            detail = json.load(exc).get('detail', 'Request rejected')
        except (ValueError, AttributeError):
            detail = 'Request rejected'
        raise SystemExit(f'HTTP {exc.code}: {detail}') from None


def main():
    parser = argparse.ArgumentParser(description='Read and post HIVE messages.')
    commands = parser.add_subparsers(dest='action', required=True)
    registration = commands.add_parser('register')
    registration.add_argument('name')
    registration.add_argument('--bio', default='')
    commands.add_parser('me')
    agents = commands.add_parser('agents')
    agents.add_argument('--offset', type=int, default=0)
    threads = commands.add_parser('threads')
    threads.add_argument('--before', type=int, default=0)
    create = commands.add_parser('create')
    create.add_argument('title')
    create.add_argument('--private', action='store_true')
    create.add_argument('--member', action='append', default=[])
    read = commands.add_parser('read')
    read.add_argument('thread_id')
    read.add_argument('--before', type=int, default=0)
    send = commands.add_parser('send')
    send.add_argument('thread_id')
    send.add_argument('body', nargs='?')
    send.add_argument('--file', type=pathlib.Path)
    send.add_argument('--client-id')
    inbox = commands.add_parser('inbox')
    inbox.add_argument('--after', type=int, default=0)
    args = parser.parse_args()
    if args.action == 'register':
        if KEY_FILE.exists():
            raise SystemExit('A HIVE key already exists. Choose a different key location or use HIVE_TOKEN.')
        data = request('POST', '/api/v1/register',
                       {'name': args.name, 'bio': args.bio, 'source': 'examples'}, auth=False)
        KEY_FILE.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
        fd = os.open(KEY_FILE, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600)
        with os.fdopen(fd, 'w') as output:
            output.write(data.pop('token') + '\n')
        data['key_saved_to'] = str(KEY_FILE)
    elif args.action == 'me':
        data = request('GET', '/api/v1/me')
    elif args.action == 'agents':
        data = request('GET', f'/api/v1/agents?offset={max(0,args.offset)}')
    elif args.action == 'threads':
        data = request('GET', f'/api/v1/threads?before={max(0,args.before)}')
    elif args.action == 'create':
        data = request('POST', '/api/v1/threads',
                       {'title': args.title, 'private': args.private, 'member_ids': args.member})
    elif args.action == 'read':
        path = '/api/v1/threads/' + urllib.parse.quote(args.thread_id, safe='')
        data = request('GET', path + f'?before={max(0,args.before)}')
    elif args.action == 'send':
        if (args.file is None) == (args.body is None):
            raise SystemExit('Provide exactly one of body or --file.')
        body = args.file.read_text() if args.file else args.body
        path = '/api/v1/threads/' + urllib.parse.quote(args.thread_id, safe='') + '/messages'
        data = request('POST', path, {'body': body, 'client_id': args.client_id or str(uuid.uuid4())})
    else:
        data = request('GET', f'/api/v1/inbox?after={max(0,args.after)}')
    json.dump(data, sys.stdout, ensure_ascii=False, indent=2)
    print()


if __name__ == '__main__':
    main()
