#!/usr/bin/env python3
"""Read immutable raw; no PHP/DB execution. Do not trust recorded matches flags."""
import copy
import hashlib
import json
from pathlib import Path

ROOT = Path(__file__).resolve().parent
RAW = ROOT / 'private-evidence/B-transport-raw.json'
EXPECTED = [
    ('0.005000000000000001', '7c14ae47e17a743f', '7b14ae47e17a743f'),
    ('1.0050000000000001', '15ae47e17a14f03f', '14ae47e17a14f03f'),
    ('12.344999999999999', '703d0ad7a3b02840', '713d0ad7a3b02840'),
]
RUNNER_SHA = '06869044c8e92df7c5e23b479378bf03acaa326bb0df2df1b27f2a6733e16db1'


def verify(data):
    checks = 0
    def check(value):
        nonlocal checks
        assert value
        checks += 1
    events = data['events']
    check(len(events) == 28)
    check([e['event'] for e in events] == ['runtime', 'identity'] + ['started', 'result'] * 12 + ['completion', 'released'])
    runtime = events[0]['data']
    check(runtime['runner_sha256'] == RUNNER_SHA)
    check(runtime['PHP_VERSION'] == '7.3.33' and runtime['precision'] == '14' and runtime['serialize_precision'] == '-1')
    check(runtime['driver'] == 'mysql' and 'mysqlnd' in runtime['client'] and runtime['php_int_size'] == 8)
    identity = events[1]['data']
    check(identity['sql'] == 'SELECT VERSION() AS version, @@SESSION.sql_mode AS sql_mode, @@character_set_connection AS charset_connection')
    check(identity['rows'] == [{'version': '5.6.50-log', 'sql_mode': 'NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION', 'charset_connection': 'utf8'}])
    for i, (lexeme, original_hex, n_hex) in enumerate(EXPECTED):
        for j, mode in enumerate(['S', 'OS', 'N', 'ON']):
            started = events[2 + 2 * (i * 4 + j)]['data']
            result = events[3 + 2 * (i * 4 + j)]['data']
            check(started['case'] == result['case'] == lexeme and started['mode'] == result['mode'] == mode)
            check(started['sql'] == 'SELECT ? + 0e0 AS x')
            check(started['pdo_type'] == (1 if mode in ('OS', 'ON') else 2))
            if mode in ('S', 'OS'):
                check(started['bind'] == {'type': 'string', 'value': lexeme})
            else:
                check(started['bind']['type'] == 'double' and started['bind']['hex_le'] == original_hex)
            check(result['x']['type'] == 'double')
            check(result['x']['hex_le'] == (n_hex if mode == 'N' else original_hex))
            check(result['expected_hex_le'] == (n_hex if mode == 'N' else original_hex))
    check(events[-2]['data'] == {'explicit_SELECT_executions': 13, 'prepares': 2, 'DDL': 0, 'DML': 0, 'HTTP': 0, 'natural_queries': 0})
    check(events[-1]['data'] == {'pdo_references_released': True})
    return checks


def main():
    original = json.loads(RAW.read_bytes())
    assertions = verify(original)
    mutants = []
    x = copy.deepcopy(original); x['events'][3]['data']['x']['hex_le'] = '0000000000000000'; mutants.append(x)
    x = copy.deepcopy(original); x['events'][7]['data']['x']['hex_le'] = EXPECTED[0][1]; mutants.append(x)
    x = copy.deepcopy(original); x['events'][4]['data']['mode'] = 'S'; mutants.append(x)
    x = copy.deepcopy(original); del x['events'][6:8]; mutants.append(x)
    x = copy.deepcopy(original); x['events'][2]['data']['sql'] = 'SELECT power FROM ydy_nutrition'; mutants.append(x)
    x = copy.deepcopy(original); x['events'][0]['data']['precision'] = '17'; mutants.append(x)
    x = copy.deepcopy(original); x['events'][6]['data']['pdo_type'] = 1; mutants.append(x)
    x = copy.deepcopy(original); x['events'][-2]['data']['DML'] = 1; mutants.append(x)
    rejected = 0
    for x in mutants:
        try: verify(x)
        except (AssertionError, KeyError, IndexError): rejected += 1
    assert rejected == len(mutants)
    assert hashlib.sha256((ROOT/'private-evidence/b-transport.php').read_bytes()).hexdigest() == RUNNER_SHA
    print(json.dumps({'status': 'PASS_ACTUAL_PDO_SERVER_TRANSPORT', 'assertions': assertions, 'mutants_rejected': rejected, 'cases': 12, 'SELECT': 13, 'DDL': 0, 'DML': 0, 'HTTP': 0, 'raw_sha256': hashlib.sha256(RAW.read_bytes()).hexdigest(), 'raw_mode': oct(RAW.stat().st_mode & 0o777), 'runtime_files_created': 0, 'SQL_cleanup': 0}, indent=2))


if __name__ == '__main__':
    main()
