"""Prove that two Strategy Tester runs traded identically by comparing their deal lists.

Compiled .ex5 files differ on every compile, so comparing files proves nothing. The deals
are what matter: time, type, direction, volume and price of every deal must match.

Usage:
    python compare_deals.py before.htm after.htm
    python compare_deals.py before.htm after.htm --money   # also compare profit and balance

Reports are the HTML files the tester saves (UTF-16LE). Exit code 0 = identical.
"""
import argparse
import html
import re
import sys

ROW = re.compile(r"<tr[^>]*>(.*?)</tr>", re.S | re.I)
CELL = re.compile(r"<td[^>]*>(.*?)</td>", re.S | re.I)
TAG = re.compile(r"<[^>]+>")


def read_deals(path):
    raw = open(path, "rb").read()
    text = raw.decode("utf-16") if raw[:2] in (b"\xff\xfe", b"\xfe\xff") else raw.decode("utf-8", "ignore")
    start = text.find(">Deals<")
    if start < 0:
        raise SystemExit(f"{path}: no Deals table")
    deals, header = [], None
    for row in ROW.findall(text[start:]):
        cells = [html.unescape(TAG.sub("", c)).strip() for c in CELL.findall(row)]
        if not cells:
            continue
        if header is None:
            if cells[0] == "Time":
                header = cells
            continue
        if len(cells) != len(header):
            break                                   # end of the table
        d = dict(zip(header, cells))
        if d["Type"] in ("buy", "sell"):            # skip the balance row
            deals.append(d)
    return deals


def key(d, money):
    k = (d["Time"], d["Type"], d["Direction"], d["Volume"], d["Price"])
    return k + ((d["Profit"].replace(" ", ""), d["Balance"].replace(" ", "")) if money else ())


def main():
    ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    ap.add_argument("a")
    ap.add_argument("b")
    ap.add_argument("--money", action="store_true", help="also compare profit and balance")
    a = ap.parse_args()
    da, db = read_deals(a.a), read_deals(a.b)
    same = 0
    for x, y in zip(da, db):
        if key(x, a.money) != key(y, a.money):
            print("first difference:")
            print("  A:", " | ".join(key(x, a.money)))
            print("  B:", " | ".join(key(y, a.money)))
            break
        same += 1
    print(f"{same}/{max(len(da), len(db))} deals identical (A has {len(da)}, B has {len(db)})")
    sys.exit(0 if same == len(da) == len(db) else 1)


if __name__ == "__main__":
    main()
