"""Read-only Alpaca account check. No deposits, orders or trading clearance."""
import argparse
import json
import os
import re
import sys
from datetime import datetime, timezone
from pathlib import Path
from urllib.request import Request, build_opener
from urllib.error import HTTPError, URLError
from urllib.parse import urlsplit
sys.path.insert(0, str(Path(__file__).resolve().parent/'runtime'))
from alpaca_reader import NoRedirect, account_amount
from engine import Rejected

PAPER = 'https://paper-api.alpaca.markets'
LIVE = 'https://api.alpaca.markets'
DATA = 'https://data.alpaca.markets'


def read_json(url, headers):
    target = urlsplit(url)
    allowed = ((target.netloc in ('paper-api.alpaca.markets','api.alpaca.markets') and target.path == '/v2/account')
        or (target.netloc == 'data.alpaca.markets' and target.path == '/v1beta3/crypto/us/latest/quotes'))
    if target.scheme != 'https' or target.fragment or not allowed:
        raise Rejected('Only exact read-only account and crypto data endpoints permitted')
    try:
        with build_opener(NoRedirect).open(Request(url, headers=headers, method='GET'), timeout=8) as r:
            raw = r.read(1000001)
            if len(raw) > 1000000: raise Rejected('Oversized broker response')
            return json.loads(raw, parse_float=str)
    except HTTPError as exc:
        raise Rejected('Read-only request rejected, HTTP '+str(exc.code)) from None
    except (URLError, OSError, TimeoutError, UnicodeError, json.JSONDecodeError):
        raise Rejected('Read-only connection unavailable; no fallback data used') from None


def account_credentials(settings, mode):
    if mode not in ('paper','live'): raise Rejected('Explicit paper/live read-only mode required')
    base = PAPER if mode == 'paper' else LIVE
    supplied = settings.get('ALPACA_BASE_URL', base)
    if supplied not in (base,base+'/',base+'/v2',base+'/v2/'):
        raise Rejected('Endpoint does not match requested account mode')
    prefix = 'ALPACA_PAPER_' if mode == 'paper' else 'ALPACA_LIVE_'
    key, secret = settings.get(prefix+'KEY'), settings.get(prefix+'SECRET')
    for value in (key,secret):
        if not isinstance(value,str) or not re.fullmatch(r'[A-Za-z0-9]{10,128}',value) or any(
                token in value.lower() for token in ('placeholder','mock','change_me','your_','your-')):
            raise Rejected('Fresh credentials required in the matching account environment variables')
    if mode == 'live' and (key.startswith('PK') or key == settings.get('ALPACA_PAPER_KEY')):
        raise Rejected('Paper credential marker/mismatch: live authentication not attempted')
    return base, {'APCA-API-KEY-ID':key,'APCA-API-SECRET-KEY':secret}


class AlpacaLiveOnboardingAuditor:
    def __init__(self, settings=None, mode='paper', *, get=read_json):
        self.settings = dict(os.environ) if settings is None else dict(settings)
        self.mode, self.get = mode, get

    def audit_onboarding_gate_status(self):
        report = {'observed_at':datetime.now(timezone.utc).isoformat(),'mode':'READ_ONLY_'+self.mode.upper(),
            'status':'CONNECTION_NOT_VERIFIED','broker_orders_submitted':0,'trial_started':False,
            'deposit_eligibility':'NOT_DETERMINED','live_clearance_granted':False}
        try:
            base, headers = account_credentials(self.settings,self.mode)
            account = self.get(base+'/v2/account',headers)
            if not isinstance(account,dict) or not isinstance(account.get('status'),str) or not account['status']:
                raise Rejected('Malformed account response')
            amounts = {k:account_amount(account.get(k)) for k in ('cash','equity','buying_power')}
            flags = {k:account.get(k) for k in ('trading_blocked','account_blocked','transfers_blocked','trade_suspended_by_user')}
            if any(v is not None and type(v) is not bool for v in flags.values()):
                raise Rejected('Malformed account restriction flag')
            report.update(status='ACCOUNT_READ_AUTHENTICATED', endpoint=base,
                account_status=account['status'],reported_amounts=amounts,reported_restriction_flags=flags,
                restrictions_complete=all(type(v) is bool for v in flags.values()))
        except Rejected as exc:
            report['reason'] = str(exc)
        return report


def main():
    p=argparse.ArgumentParser(description=__doc__)
    p.add_argument('--mode',choices=('paper','live'),default='paper')
    args=p.parse_args()
    report=AlpacaLiveOnboardingAuditor(mode=args.mode).audit_onboarding_gate_status()
    print(json.dumps(report,indent=2,allow_nan=False))
    return 0 if report['status']=='ACCOUNT_READ_AUTHENTICATED' else 1


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