"""One current-host acceptance receipt. No seeding, broker orders or production clearance."""
import argparse,asyncio,json,os,sqlite3,subprocess,sys,uuid,hashlib
from pathlib import Path
from datetime import datetime,timezone
from infinbot_common import private_read,private_dir,atomic_json,strict_json,digest,timestamp,Rejected
from ledger_reporting import read_snapshot
from risk_state import RiskState
from generated.verify_ledger_json import ProductionLedgerJsonAuditor
from generated.worker_performance_ranker import MultiWorkerPerformanceRanker
from score_validator_v4 import RollingEliteGatekeeper
from feed_probe import crypto_stream,broker_positions,reconcile,futures_status,reconcile_balances
from verify_live_feeds_standalone import load_private_credentials,account_credentials,authenticate_account,read_json,validate_quotes
from infinbot_backup import backup
from infinbot_secret_audit import audit as audit_signing_token
from datamine_adapter import inspect_saved
from test_backup_recovery import execute_non_destructive_backup_test,REQUIRED_TABLES

ROOT=Path(__file__).resolve().parent


def execute(config,*,network=True,include_backup=True):
    checks=[];report={'product':'InFinBot','observed_at':timestamp(),'scope':'Current installed host; source ledger read-only',
                      'checks':checks,'broker_orders_submitted':0,'ledger_seeded':False,'production_release':'BLOCKED',
                      'live_execution_enabled':False,'lgc_contract_modified':False}
    def check(name,fn,passed=lambda r:True,mandatory=True):
        try:
            result=fn();ok=passed(result)
            checks.append({'check':name,'status':'PASS' if ok else 'BLOCKED','mandatory':mandatory,'result':result})
            return result
        except Exception:
            checks.append({'check':name,'status':'BLOCKED','mandatory':mandatory,'reason':'Missing, incompatible or unavailable current evidence; no fallback or raw secret displayed'})
            return None
    snapshot=check('current_ledger',lambda:read_snapshot(config['db_path']),lambda x:x['data_origin']!='SYNTHETIC_FIXTURE')
    from rebalance_engine import QuantRiskRebalanceEngine
    check('zero_entry_policy',lambda:QuantRiskRebalanceEngine(config['db_path'],config['risk_config_out']).execute_dynamic_rebalance(),
          lambda x:not x['live_execution_enabled'] and all(not w['enabled'] for w in x['worker_allocations'].values()))
    check('actual_json_export',lambda:ProductionLedgerJsonAuditor(config['export_path']).validate(),lambda x:x['status']=='PASS')
    def rankings():
        r=MultiWorkerPerformanceRanker(config['db_path'])
        try:return r.execute_worker_ranking_audit(config['worker_scope'])
        finally:r.close()
    check('recorded_worker_rankings',rankings,lambda x:x['status']=='RECORDED_RANKING_COMPLETE')
    def scores():
        r=RollingEliteGatekeeper(config['db_path'],execution_tag=config['worker_scope'],read_only=True)
        try:return r.execute_rolling_window_audit()
        finally:r.close()
    check('rolling_100_session_research_gate',scores,lambda x:x['DECISION_TOKEN']=='RESEARCH_SCORE_THRESHOLD_MET_NO_LIVE_CLEARANCE')
    check('persistent_entry_freeze',lambda:RiskState(config['risk_state']).status(),lambda x:x['entries_frozen'] and not x['deadline_expired'])
    for worker in ('bot-worker-crypto','bot-worker-futures'):
        def once(worker=worker):
            p=subprocess.run([sys.executable,str(ROOT/'runtime/worker.py'),'--worker',worker,'--db-path',config['db_path'],
                              '--state-path',config['risk_state'],'--once'],capture_output=True,text=True,timeout=15)
            if p.returncode:raise Rejected('Worker process blocked')
            return strict_json(p.stdout)
        check(worker+'_execution',once,lambda x:x['allocated_units']=='0.0000' and not x['live_execution_enabled'])
    # No client commands or fake "processed" receipt is used by this health check.
    from infinbot_gateway_check import rehearse
    check('gateway_host_rehearsal',lambda:asyncio.run(rehearse(config)))
    if network:
        credentials=None
        try:
            credentials={}
            _,headers=account_credentials(credentials,'paper')
            check('proxy_route_configuration',lambda:{'status':'PROXY_ONLY','proxy_base_url':'https://sotality.com','broker_credential_files_read':False})
        except Exception:
            credentials=None
            checks.append({'check':'private_paper_configuration','status':'BLOCKED','mandatory':True,'reason':'Private paper credentials missing or invalid; never logged'})
        if credentials is not None:
            check('proxy_account_response_validation',lambda:authenticate_account(read_json,headers),lambda x:x=='PROXY_ACCOUNT_READ_VALIDATED')
            checks.append({'check':'proxy_upstream_account_mode','status':'UNVERIFIED','mandatory':True,'reason':'Proxy upstream paper/live mode and access contract require server evidence'})
            if snapshot:check('proxy_cash_equity_reconciliation',lambda:reconcile_balances(snapshot,read_json('https://sotality.com/v2/account',headers)),lambda x:x['status']=='BALANCE_RECONCILIATION_MATCH')
            quote_url='https://sotality.com/v1beta3/crypto/us/latest/quotes?symbols=BTC%2FUSD%2CETH%2FUSD'
            check('fresh_crypto_rest',lambda:validate_quotes(read_json(quote_url,headers),['BTC/USD','ETH/USD'],datetime.now(timezone.utc)))
            check('fresh_crypto_stream',lambda:asyncio.run(crypto_stream(credentials)),lambda x:x['status']=='FRESH_CRYPTO_STREAM_OBSERVED')
            if snapshot:check('paper_broker_position_reconciliation',lambda:reconcile(snapshot['positions'],broker_positions(credentials)),lambda x:x['status']=='POSITION_RECONCILIATION_MATCH')
    else:checks.append({'check':'broker_and_feeds','status':'UNVERIFIED','mandatory':True,'reason':'Network checks explicitly skipped'})
    check('process_signing_token_configuration',lambda:audit_signing_token(config.get('hmac_token_file'),keychain_service=config.get('hmac_keychain_service')),
          lambda x:x['status']=='PROCESS_PLACEHOLDER_ABSENT_EXTERNAL_TOKEN_LOADED')
    if config.get('datamine_config'):
        check('futures_datamine_saved_schema',lambda:inspect_saved(strict_json(private_read(config['datamine_config']))))
    else:
        checks.append({'check':'futures_datamine_saved_schema','status':'UNVERIFIED','mandatory':True,
                       'reason':'CME DataMine identified; select existing saved metadata/file and explicit supported dataset schema. Existing configuration preserved.'})
    checks.append({'check':'current_futures_delivery','status':'UNVERIFIED','mandatory':True,'result':futures_status()})
    checks.append({'check':'exposed_credential_revocation','status':'UNVERIFIED','mandatory':True,
                   'reason':'Fresh authentication cannot establish revocation of old keys; broker-side revocation evidence and review required'})
    check('independent_native_snapshot_drill',lambda:execute_non_destructive_backup_test(config['db_path'],required_tables=config.get('backup_required_tables',REQUIRED_TABLES)),
          lambda x:x['status']=='NATIVE_SNAPSHOT_REOPEN_AND_SCHEMA_COUNTS_VERIFIED')
    if include_backup:check('current_encrypted_backup_and_restore',lambda:backup(config))
    else:checks.append({'check':'current_encrypted_backup_and_restore','status':'UNVERIFIED','mandatory':True,'reason':'Backup explicitly skipped'})
    def schedule():
        p=subprocess.run(['crontab','-l'],capture_output=True,text=True,timeout=5)
        if p.returncode or '# INFINBOT_HOST_JOBS_V1' not in p.stdout:raise Rejected('Installed host jobs missing')
        return {'status':'HOST_SCHEDULE_READ_BACK','first_scheduled_run_verified':False}
    check('installed_host_schedule',schedule)
    check('notification_receipt',lambda:strict_json(private_read(config['notification_receipt_file'])),
          lambda x:x.get('device_delivery')=='OWNER_CONFIRMED' and 0<=(datetime.now(timezone.utc)-datetime.fromisoformat(x['observed_at'])).total_seconds()<=86400)
    report['technical_checks_passed']=sum(x['status']=='PASS' for x in checks)
    report['blocking_checks']=[x['check'] for x in checks if x['mandatory'] and x['status']!='PASS']
    report['status']='HOST_CHECKS_COMPLETED_BLOCKERS_REMAIN' if report['blocking_checks'] else 'HOST_CHECKS_COMPLETED_REVIEW_REQUIRED'
    report['lgc_release_status']='OUTSIDE_THIS_REPAIR_SCOPE'
    report['visual_layout_status']='REQUIRES_HOST_BROWSER_REVIEW'
    report['remote_gateway_tls_status']='NOT_TESTED_BY_LOOPBACK_REHEARSAL'
    return report


def main():
    p=argparse.ArgumentParser(description=__doc__);p.add_argument('--config',required=True)
    p.add_argument('--offline',action='store_true');p.add_argument('--skip-backup',action='store_true')
    p.add_argument('--datamine-config',help='Existing private DataMine file/schema mapping; host config remains unchanged')
    p.add_argument('--hmac-token-file',help='Existing externally managed private signing token file; no inline secret')
    p.add_argument('--hmac-keychain-service',help='Existing Mac Keychain signing service name; no inline secret')
    args=p.parse_args()
    try:
        config_bytes=private_read(args.config)
        config=strict_json(config_bytes);private_dir(config['receipt_dir'])
        if args.datamine_config:config['datamine_config']=args.datamine_config
        if args.hmac_token_file:config['hmac_token_file']=args.hmac_token_file
        if args.hmac_keychain_service:config['hmac_keychain_service']=args.hmac_keychain_service
        report=execute(config,network=not args.offline,include_backup=not args.skip_backup)
        unchanged=hashlib.sha256(private_read(args.config)).digest()==hashlib.sha256(config_bytes).digest()
        report['host_config_unchanged_during_run']=unchanged
        if not unchanged:
            report['blocking_checks'].append('host_config_changed_during_run')
            report['status']='HOST_CHECKS_COMPLETED_BLOCKERS_REMAIN'
        target=Path(config['receipt_dir'])/('infinbot_acceptance_'+uuid.uuid4().hex+'.json')
        atomic_json(target,report)
        print(json.dumps({'status':report['status'],'receipt_path':str(target),'blocking_checks':report['blocking_checks'],
                          'broker_orders_submitted':0,'live_execution_enabled':False},indent=2))
        return 1 if report['blocking_checks'] else 0
    except Exception:print(json.dumps({'status':'ACCEPTANCE_BLOCKED','reason':'Host configuration missing or unsafe; no records seeded','live_execution_enabled':False}));return 1


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