"""Read-only exact Deployment and admission boundaries; no mutation authority."""
import copy
import hashlib
import json

BASE = 'forgejo.coulomb.social/coulomb/informed-decision@sha256:763c36402c8be7cc4c1bd1a61623d1aff9116d52241877425b45a7018cc0883a'
CANDIDATE = 'forgejo.coulomb.social/coulomb/informed-decision@sha256:f5588f496b1f267d07cdc9f5208e6f2f241f74b739c23924b03702dec13a5c23'


def dependency_projection(configmap, pvc):
    if (configmap.get('kind') != 'ConfigMap' or configmap.get('immutable') is not True
            or configmap['metadata']['namespace'] != 'informed-decision'
            or configmap['metadata']['name'] != 'informed-decision-runtime-6c221878d051'
            or set(configmap.get('data', {})) != {'runtime.json'}
            or configmap.get('binaryData')):
        raise ValueError('unexpected immutable runtime config identity')
    if (pvc.get('kind') != 'PersistentVolumeClaim'
            or pvc['metadata']['namespace'] != 'informed-decision'
            or pvc['metadata']['name'] != 'informed-decision-data'
            or pvc.get('status', {}).get('phase') != 'Bound'
            or not pvc.get('spec', {}).get('volumeName')):
        raise ValueError('unexpected bound PVC custody')
    config = projection(configmap)
    config.pop('data')
    config['canonical_data_sha256'] = hashlib.sha256(json.dumps(
        configmap['data'], sort_keys=True, separators=(',', ':')).encode()).hexdigest()
    return {'configmap': config, 'pvc': projection(pvc), 'pvc_phase': 'Bound'}


def check_dependencies(configmap, pvc, sealed):
    if dependency_projection(configmap, pvc) != sealed:
        raise ValueError('runtime config or PVC identity/custody changed')


def projection(value):
    value = copy.deepcopy(value)
    value.pop('status', None)
    for key in ('resourceVersion', 'generation', 'creationTimestamp', 'managedFields'):
        value['metadata'].pop(key, None)
    for key in ('kubectl.kubernetes.io/last-applied-configuration', 'deployment.kubernetes.io/revision'):
        value['metadata'].get('annotations', {}).pop(key, None)
    return value


def check_current(current, sealed):
    if projection(current) != sealed:
        raise ValueError('sealed live UID or configuration changed')


def check_admitted(admitted, sealed):
    expected = copy.deepcopy(sealed)
    containers = expected['spec']['template']['spec']['containers']
    if len(containers) != 1 or containers[0]['name'] != 'informed-decision' or containers[0]['image'] != BASE:
        raise ValueError('unexpected baseline container identity')
    containers[0]['image'] = CANDIDATE
    if projection(admitted) != expected:
        raise ValueError('admission changed configuration beyond the sole image pin')


def transport_result(exit_code, output):
    import json
    try:
        value = json.loads(output)
    except (ValueError, TypeError):
        return {'all_checks_pass': False, 'reason': 'invalid transport result'}
    if exit_code != 0 or not isinstance(value, dict) or value.get('all_checks_pass') is not True:
        return {'all_checks_pass': False, 'reason': 'read-only preflight refused'}
    return value
