import json, sys
from pathlib import Path

def token_at(document, path):
    value = document
    inherited = None
    for part in path.split('.'):
        inherited = value.get('$type', inherited)
        value = value[part]
    return value, value.get('$type', inherited)

def resolve(document, value, seen=()):
    if isinstance(value, str) and value.startswith('{') and value.endswith('}'):
        path = value[1:-1]
        if path in seen:
            raise ValueError('cyclic reference: ' + path)
        token, _ = token_at(document, path)
        return resolve(document, token['$value'], seen + (path,))
    return value

def main():
    document = json.loads(Path(sys.argv[1] if len(sys.argv)>1 else 'tokens.json').read_text())
    contract = json.loads(Path('consumer-map.json').read_text())
    rows, errors = [], []
    for item in contract['tokens']:
        try:
            token, kind = token_at(document, item['path'])
            value = resolve(document, token['$value'])
            if kind != item['expectedType']:
                raise ValueError('type ' + repr(kind) + ' != ' + item['expectedType'])
            actual = value.get('hex', '').lower() if kind == 'color' and isinstance(value, dict) else value
            if actual != item['expectedValue']:
                raise ValueError('resolved value mismatch: ' + repr(actual))
            rows.append({'path': item['path'], 'type': kind, 'resolvedValue': actual})
        except (KeyError, ValueError, TypeError) as error:
            errors.append({'path': item['path'], 'error': str(error)})
    print(json.dumps({'identity': 'author_project_contract_not_official_CLI_or_full_DTCG_validator', 'rows': rows, 'errors': errors, 'passed': not errors}, ensure_ascii=False, indent=2))
    return 1 if errors else 0

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