"""ChinaOPC standard-library client. Submission requires explicit owner consent flags.
No uploads, crawling, code execution from articles, or automatic publication.
"""
import argparse, hashlib, json, os, sys, uuid
from pathlib import Path
from urllib.error import HTTPError
from urllib.request import Request, urlopen


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--file', required=True, help='UTF-8 project JSON')
    parser.add_argument('--base', choices=['https://chinaopc.com', 'http://127.0.0.1:8787'], default='https://chinaopc.com')
    parser.add_argument('--submit', action='store_true', help='Actually transmit the project and contact details')
    parser.add_argument('--accept-agreement')
    parser.add_argument('--authorized', action='store_true')
    parser.add_argument('--privacy-consent', action='store_true')
    parser.add_argument('--hong-kong-storage-consent', action='store_true')
    parser.add_argument('--receipt', default='private-receipt.json')
    parser.add_argument('--idempotency-key', help='Reuse the original random key when retrying')
    args = parser.parse_args()
    endpoint = args.base + '/api/v1/submissions'

    def call(url, data=None, headers=None):
        raw = None if data is None else json.dumps(data, ensure_ascii=False).encode('utf-8')
        if raw and len(raw) > 98304:
            raise ValueError('Request exceeds 96 KiB.')
        request = Request(url, data=raw, headers={'User-Agent': 'ChinaOPC-SubmissionClient/1.0', **({'Content-Type': 'application/json'} if raw else {}), **(headers or {})})
        try:
            with urlopen(request, timeout=30) as response:
                return json.load(response)
        except HTTPError as error:
            try: message = json.load(error).get('error', {}).get('message', 'Request failed')
            except Exception: message = 'Request failed'
            raise ValueError(f'HTTP {error.code}: {message}. Respect Retry-After and avoid repeated submissions.') from None

    path = Path(args.file)
    if path.stat().st_size > 98304:
        raise ValueError('Project JSON exceeds 96 KiB.')
    payload = json.loads(path.read_text(encoding='utf-8'))
    rules = call(endpoint + '/rules')
    if not args.submit:
        print(json.dumps({'mode': 'no_submission', 'agreement_url': rules['agreement_url'], 'version': rules['version'], 'sha256': rules['sha256'], 'message': 'No project or contact fields transmitted. Have the responsible owner review the agreement and complete all consent flags before --submit.'}, ensure_ascii=False, indent=2))
        return
    if not (args.accept_agreement == rules['version'] and args.authorized and args.privacy_consent and args.hong_kong_storage_consent):
        raise ValueError('Explicit current agreement, owner authorization, privacy and Hong Kong storage consent flags are required.')
    if payload.get('agreement', {}).get('sha256') != rules['sha256']:
        raise ValueError('Agreement hash changed or is absent. The owner must reread and confirm the current agreement before submission.')
    receipt_path = Path(args.receipt)
    if receipt_path.exists():
        raise ValueError('Receipt file already exists. Preserve it; use a new private path or query the original receipt.')
    key = args.idempotency_key or uuid.uuid4().hex
    # Reserve a private recovery record before any transmission. Preserve this key after network errors.
    descriptor = os.open(receipt_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
    os.close(descriptor)
    receipt_path.write_text(json.dumps({'idempotency_key': key, 'status': 'prepared', 'message': 'If transmission fails, reuse this key and the original content. This file may later contain a private status token.'}), encoding='utf-8')
    payload['agreement'] = {'version': rules['version'], 'sha256': rules['sha256'], 'accepted': True, 'authorized': True, 'privacy_accepted': True, 'hong_kong_storage_accepted': True}
    challenge = call(endpoint + '/challenge', {'name': payload['submitter']['name'], 'email': payload['submitter']['email']})
    nonce = 0
    while not hashlib.sha256(f"{challenge['challenge']}:{nonce}".encode()).hexdigest().startswith(challenge['prefix']):
        nonce += 1
        if nonce > 2000000:
            raise ValueError('Challenge not solved within the client limit; retry later.')
    payload['proof'] = {'challenge': challenge['challenge'], 'nonce': str(nonce)}
    receipt = call(endpoint, payload, {'Idempotency-Key': key})
    receipt_path.write_text(json.dumps({'idempotency_key': key, **receipt}, ensure_ascii=False, indent=2), encoding='utf-8')
    print(f"Received {receipt['submission_id']}; status {receipt['status']}. Private receipt saved to {receipt_path}. No automatic publication.")


if __name__ == '__main__':
    try: main()
    except (ValueError, OSError, KeyError) as error:
        print(str(error), file=sys.stderr)
        sys.exit(1)
