#!/usr/bin/env python3
"""Portable stdio bridge to Auro's authenticated HTTPS MCP. Python stdlib only.

Credentials are read from the calling agent's secret environment, never from
prompts or command arguments. No redirects, retries, browser or Google login.
"""
import base64
import json
import os
import re
import sys
import urllib.error
import urllib.parse
import urllib.request


class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, *args, **kwargs):
        return None


def apply_toolset(request, toolset):
    """Limit advertised tools only; explicit calls and credentials are unchanged."""
    if toolset not in ('full', 'film', 'graphics', 'editing', 'audio'):
        raise ValueError('AUROFLOW_MCP_TOOLSET must be full, film, graphics, editing or audio')
    if toolset=='full' or not isinstance(request,dict) or request.get('method')!='tools/list':
        return request
    params=request.get('params',{})
    if not isinstance(params,dict) or not isinstance(params.get('_meta',{}),dict):
        return request  # Let the server reject malformed MCP parameters.
    meta=dict(params.get('_meta',{}));meta.setdefault('auroflow/toolset',toolset)
    return {**request,'params':{**params,'_meta':meta}}


def main():
    toolset=os.environ.get('AUROFLOW_MCP_TOOLSET','full')
    if toolset not in ('full','film','graphics','editing','audio'):
        raise SystemExit('AUROFLOW_MCP_TOOLSET must be full, film, graphics, editing or audio')
    endpoint = os.environ.get("AUROFLOW_MCP_URL", "https://api.auroflow.club/v1/mcp")
    url = urllib.parse.urlsplit(endpoint)
    if url.scheme != "https" or url.username or url.password or url.query or url.fragment or url.path != "/v1/mcp":
        raise SystemExit("AUROFLOW_MCP_URL must be an HTTPS /v1/mcp endpoint without credentials/query")
    email, password = os.environ.get("AUROFLOW_API_EMAIL"), os.environ.get("AUROFLOW_API_PASSWORD")
    token = os.environ.get('AUROFLOW_API_TOKEN')
    if token:
        if email or password or not re.fullmatch(r'afk_[a-f0-9]{32}_[A-Za-z0-9_-]{43}', token):
            raise SystemExit('Use one valid secure authentication source: agent token or Basic credentials')
        auth = 'Bearer ' + token
    else:
        if not email or not password or ":" in email:
            raise SystemExit("Set AUROFLOW_API_TOKEN or AUROFLOW_API_EMAIL/AUROFLOW_API_PASSWORD in your secure environment")
        auth = "Basic " + base64.b64encode((email + ":" + password).encode()).decode()
    opener = urllib.request.build_opener(NoRedirect())
    for raw in sys.stdin.buffer:
        if len(raw) > 14 * 1024 * 1024:
            raise SystemExit("MCP message exceeds size limit")
        ident = None
        try:
            request = json.loads(raw)
            ident = request.get("id")
            headers = {"Authorization": auth, "Content-Type": "application/json",
                "Accept": "application/json, text/event-stream", "MCP-Protocol-Version": "2025-11-25",
                "User-Agent": "AUROFLOW-MCP-Client/1.0"}
            prepared=apply_toolset(request,toolset)
            body=raw if prepared is request else json.dumps(prepared,ensure_ascii=False,allow_nan=False).encode()
            req = urllib.request.Request(endpoint, data=body, headers=headers, method="POST")
            with opener.open(req, timeout=190) as response:
                body = response.read(4 * 1024 * 1024 + 1)
                if response.status == 202 and not body:
                    continue
                if len(body) > 4 * 1024 * 1024:
                    raise ValueError("response too large")
                result = json.loads(body)
        except urllib.error.HTTPError as exc:
            # Never forward an HTML error page or a server message that might
            # echo a credential. Keep only bounded public diagnostics.
            status = exc.code
            support = exc.headers.get('X-Auro-Request-ID', '') if exc.headers else ''
            retry_after = exc.headers.get('Retry-After', '') if exc.headers else ''
            exc.close()
            if ident is None:
                continue
            data = {'http_status': status, 'automatic_retry': False,
                    'action_required': 'renew_or_check_own_agent_key' if status in (401, 403) else 'check_service_or_read_same_resource'}
            if re.fullmatch(r'[a-f0-9]{24}', support):
                data['request_id'] = support
            if re.fullmatch(r'[0-9]{1,3}', retry_after):
                data['retry_after_seconds'] = min(int(retry_after), 300)
            result = {'jsonrpc': '2.0', 'id': ident, 'error': {
                'code': -32001 if status in (401, 403) else -32000,
                'message': 'Auro authentication rejected. Check your own agent key.' if status in (401, 403) else 'Auro HTTP response rejected. No request was retried.',
                'data': data}}
        except Exception:
            if ident is None:
                continue
            result = {"jsonrpc": "2.0", "id": ident, "error": {"code": -32000,
                "message": "Auro response unavailable. Check account/service; read the SAME job/sequence ID before further action. No request was retried."}}
        sys.stdout.write(json.dumps(result, ensure_ascii=False, separators=(",", ":")) + "\n")
        sys.stdout.flush()


if __name__ == "__main__":
    main()
