"""Read-only disposition-ledger arithmetic validation. Not IRS filing clearance."""
import argparse
from datetime import datetime, timezone
from decimal import Decimal, localcontext
import hashlib
import json
from pathlib import Path
import re


def _pairs(values):
    out={}
    for k,v in values:
        if k in out:raise ValueError('Duplicate JSON key')
        out[k]=v
    return out


def amount(value):
    if type(value) not in (str,int) or not re.fullmatch(r'-?[0-9]+(?:\.[0-9]{1,6})?',str(value)) or len(str(value))>40:
        raise ValueError('Amount must be an integer or decimal string with at most six fractional digits')
    result=Decimal(str(value))
    if not result.is_finite() or abs(result)>Decimal('9000000000000000'):
        raise ValueError('Amount outside supported range')
    return result


def parsed_date(value):
    if not isinstance(value,str):raise ValueError('Date must be text')
    if re.fullmatch(r'\d{4}-\d{2}-\d{2}',value):
        return ('date',datetime.strptime(value,'%Y-%m-%d').date())
    d=datetime.fromisoformat(value.replace('Z','+00:00'))
    if d.tzinfo is None or d.utcoffset() is None:
        raise ValueError('Timestamp requires an explicit timezone offset; date-only values are also supported')
    return ('timestamp',d.astimezone(timezone.utc))


class ProductionLedgerJsonAuditor:
    def __init__(self,filepath='/Users/bpa/ForesixaQuant/generated/automated_irs_form_8949.json'):
        self.filepath=Path(filepath)
        self.last_report=None

    def validate(self):
        errors=[];warnings=[]
        base={'scope':'Read-only ledger structure, dates and exact arithmetic; not IRS schema/business-rule/tax-treatment clearance','status':'FAIL','source_sha256':None,'records_total':0,'records_valid':0,'errors':errors,'warnings':warnings,'totals':None,'irs_release_status':'UNVERIFIED'}
        try:
            if not self.filepath.is_file() or self.filepath.is_symlink() or self.filepath.stat().st_size>20*1024*1024:raise ValueError('Missing, unsafe or oversized input file')
            raw=self.filepath.read_bytes();base['source_sha256']=hashlib.sha256(raw).hexdigest()
            records=json.loads(raw.decode('utf-8'),parse_float=str,object_pairs_hook=_pairs,parse_constant=lambda x: (_ for _ in ()).throw(ValueError('Nonfinite JSON')))
            if not isinstance(records,list) or not records:raise ValueError('Ledger must be a nonempty JSON array')
        except (OSError,UnicodeError,ValueError) as exc:
            errors.append({'record':None,'issue':str(exc)});self.last_report=base;return base
        base['records_total']=len(records)
        sums={k:Decimal(0) for k in ('gross_proceeds','cost_basis','adjustments','net_gain_or_loss')}
        wins=losses=breakeven=0;seen_ids=set();seen_rows=set()
        required={'equity_symbol','date_acquired','date_sold_or_disposed','gross_proceeds','cost_basis','net_gain_or_loss'}
        with localcontext() as ctx:
            ctx.prec=100
            for index,row in enumerate(records,1):
                try:
                    if not isinstance(row,dict) or not required<=row.keys():raise ValueError('Missing required disposition fields or invalid row type')
                    if not isinstance(row['equity_symbol'],str) or not row['equity_symbol'].strip():raise ValueError('Invalid asset symbol')
                    if row.get('currency')!='USD':raise ValueError('Mixed/unsupported currency; this validator uses USD')
                    if 'transaction_id' in row:
                        tid=row['transaction_id']
                        if not isinstance(tid,str) or not tid or tid in seen_ids:raise ValueError('Invalid or repeated transaction_id')
                        seen_ids.add(tid)
                    else:
                        warnings.append({'record':index,'issue':'No transaction_id; uniqueness is limited to exact row comparison'})
                    fp=json.dumps(row,sort_keys=True,separators=(',',':'),allow_nan=False)
                    if fp in seen_rows:raise ValueError('Duplicate disposition row')
                    seen_rows.add(fp)
                    acquired=parsed_date(row['date_acquired']);sold=parsed_date(row['date_sold_or_disposed'])
                    if acquired[0]!=sold[0]:raise ValueError('Acquisition/disposal must use the same date representation')
                    if acquired[1]>sold[1]:raise ValueError('Disposal precedes acquisition')
                    proceeds=amount(row['gross_proceeds']);basis=amount(row['cost_basis']);pnl=amount(row['net_gain_or_loss']);adjustment=amount(row.get('adjustment_amount','0'))
                    if proceeds<0 or basis<0:raise ValueError('Proceeds and basis must be nonnegative')
                    if adjustment!=0 and (not isinstance(row.get('adjustment_reason'),str) or not row['adjustment_reason'].strip()):raise ValueError('Nonzero adjustment requires an adjustment_reason')
                    if pnl!=proceeds-basis+adjustment:raise ValueError('Net gain/loss does not equal proceeds minus basis plus explicit adjustment')
                    for k,v in (('gross_proceeds',proceeds),('cost_basis',basis),('adjustments',adjustment),('net_gain_or_loss',pnl)):sums[k]+=v
                    base['records_valid']+=1
                    if pnl>0:wins+=1
                    elif pnl<0:losses+=1
                    else:breakeven+=1
                except (ValueError,TypeError,OverflowError) as exc:
                    errors.append({'record':index,'issue':str(exc)})
            if not errors:
                base['status']='PASS'
                base['totals']={k:format(v,'.6f') for k,v in sums.items()}
                base['dispositions']={'wins':wins,'losses':losses,'breakeven':breakeven,'denominator':len(records),'win_rate_percent':format(Decimal(wins)*100/len(records),'.6f')}
        self.last_report=base
        return base

    def execute_integrity_verification_pass(self):
        report=self.validate();print(json.dumps(report,indent=2));return report['status']=='PASS'


if __name__=='__main__':
    parser=argparse.ArgumentParser();parser.add_argument('--file','--filepath',dest='file',default=str(Path(__file__).resolve().parent/'automated_irs_form_8949.json'));args=parser.parse_args()
    raise SystemExit(0 if ProductionLedgerJsonAuditor(args.file).execute_integrity_verification_pass() else 2)
