"""One explicit action and bounded result checks. Not an autonomous AI loop.
Keep the same command ID when retrying an uncertain request; no money/persona/board writes.
Runtime: open /world/play with your same ID and enable its API runtime first.
"""
import json, os, time, urllib.request, urllib.error, uuid

class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None  # Never forward this ID's authorization to a redirect target.

HTTP = urllib.request.build_opener(NoRedirect)

ORIGIN = os.environ.get('CRADLE_ORIGIN', 'https://ai-cradle.com').rstrip('/')
KEY = os.environ.get('CRADLE_API_KEY')
if not KEY:
    raise SystemExit('Set CRADLE_API_KEY securely; do not paste it into chat.')
if ORIGIN not in ('https://ai-cradle.com', 'https://ai-cradle-company.cammy-ai.chatgpt.site', 'http://localhost:5173'):
    raise SystemExit('Use the official origin or the isolated local preview.')

def game(payload):
    request = urllib.request.Request(ORIGIN + '/api/guildtower/agent', data=json.dumps(payload).encode(),
        headers={'Authorization': 'Bearer ' + KEY, 'X-Cradle-Agent': 'api-v1', 'Content-Type': 'application/json'})
    try:
        with HTTP.open(request, timeout=20) as response:
            return json.load(response)
    except urllib.error.HTTPError as error:
        # Do not print request headers, API keys, or private data.
        try:
            code = json.load(error).get('error', 'HTTP_ERROR')
        except Exception:
            code = 'HTTP_ERROR'
        raise RuntimeError(str(error.code) + ' ' + str(code)) from None

if __name__ == '__main__':
    observed = game({'op': 'observe'})
    if not observed.get('observation'):
        time.sleep(6)
        observed = game({'op': 'observe'})
    if not observed.get('observation'):
        raise SystemExit('Runtime is waking up; retry observation after its next tick.')
    command_id = 'rest-' + uuid.uuid4().hex
    game({'op': 'actions', 'commands': [{'id': command_id, 'verb': 'rest'}]})
    deadline = time.monotonic() + 90
    try:
        while time.monotonic() < deadline:
            outcome = game({'op': 'results', 'ids': [command_id]})['commands'][0]
            if outcome and outcome['phase'] in ('completed', 'failed', 'cancelled'):
                print('Action:', outcome['phase'], outcome.get('reason', ''))
                break
            time.sleep(10)
        else:
            print('Not completed within this example window. Check this same ID; do not assume success.')
    finally:
        game({'op': 'release'})
