"""Read-only connection diagnosis. Recovery never guesses a peer's identity."""
import ipaddress
import json
import re
import subprocess

import field_profiles as profiles
from field_ui import print, input


def explain_result(result):
    print('Phase:', result.get('phase', 'UNKNOWN'), 'attempts:', result.get('attempt_count', 'legacy/unknown'))
    if result.get('prior_attempts_unknown'):print('Earlier attempts were not counted. Count means explicit helper runs, not automatic retries.')
    print('HTTP:', result.get('http_status', 'unknown'), 'error:', result.get('error', 'unknown'))
    code = result.get('remote_code')
    print('Web code:', code or 'not recorded', 'field:', result.get('remote_field', '-'))
    reason = result.get('remote_reason')
    if result.get('phase') == 'CERTIFICATE' and reason == 'CERTIFICATE_SIGNING_NOT_CONFIGURED':
        print('Web certificate signing is not configured. Ask the Web operator to configure its existing CA certificate/key paths and reload the application.')
        print('Preserve this stage and session. Do not cancel, change the connection version or create a new CA. Retry once after the Web fix.')
    elif result.get('phase') == 'CERTIFICATE' and reason == 'CERTIFICATE_SIGNING_FAILED':
        print('Web certificate signing failed. Ask the Web operator to check CA/key validity, matching and file permissions.')
        print('Preserve this stage and session. Do not cancel, change the connection version or create a new CA. Retry once after the Web fix.')
    elif code in ('CONNECTION_VERSION_CONFLICT', 'STALE_CONNECTION_VERSION'):
        print('Connection revision rejected. Not a password error. Web current version is unknown.')
        print('Preserve failed stage: ct config cancel; ct config version NUMBER; ct config prepare')
    elif result.get('http_status') == 401:
        print('Check the account for LOGIN, or the token for CERTIFICATE. Do not increase versions for 401.')
    elif result.get('error', '').startswith(('TLS_', 'TCP_', 'DNS_', 'NETWORK_')):
        print('Check peer address, route and CA. The outcome may be unknown; do not automatically retry.')
    else:
        print('Inspect the recorded phase before ct config retry. Certificate success is not WSS acceptance.')


def neighbor(profile):
    interface = profile['network']['interface']
    peer = profiles.web(profile)['host']
    ipaddress.IPv4Address(peer)
    result = subprocess.run(['ip', '-j', 'neigh', 'show', 'to', peer, 'dev', interface],
                            check=True, capture_output=True, text=True, timeout=5)
    return json.loads(result.stdout)


def arp(args):
    p = profiles.load()
    print('Environment:', p['label'], 'interface:', p['network']['interface'], 'Web:', profiles.web(p)['host'])
    print('Kernel neighbor:', json.dumps(neighbor(p)))
    print('PERMANENT here is not reboot persistence. Never reuse a MAC from a different network.')
    if not args or args == ['status']:
        print('After independent MAC verification only: ct net arp set aa:bb:cc:dd:ee:ff')
        print('Return to dynamic discovery: ct net arp clear')
        return
    peer = profiles.web(p)['host'];interface = p['network']['interface']
    if args[0] == 'set' and len(args) == 2:
        mac = args[1].lower()
        if not re.fullmatch(r'(?:[0-9a-f]{2}:){5}[0-9a-f]{2}', mac) or int(mac[:2],16) & 1 or mac == '00:00:00:00:00:00':
            raise ValueError('Verified unicast MAC required')
        command = ['ip','neigh','replace',peer,'lladdr',mac,'nud','permanent','dev',interface]
    elif args == ['clear']:
        command = ['ip','neigh','del',peer,'dev',interface]
    else:
        raise ValueError('ct net arp status | set MAC | clear')
    if input('Change this one kernel neighbor only? Type ARP (Enter=cancel): ') != 'ARP':
        return
    import time
    target = profiles.STATE / ('neighbor-'+time.strftime('%Y%m%dT%H%M%S')+'.json')
    profiles.atomic(target, {'profile':p['id'],'peer':peer,'interface':interface,'before':neighbor(p),'command':command})
    subprocess.run(command, check=True, timeout=5)
    print('Kernel-only change:', neighbor(p), 'record:', target)
