import subprocess, json, os, time, tempfile

ROOT = '/home/claude/zc/zc'
ok = fail = 0
def check(name, cond, detail=''):
    global ok, fail
    if cond: ok += 1; print('PASS', name)
    else: fail += 1; print('FAIL', name, detail)

# Generate a fresh self-signed cert (SAN=127.0.0.1) for every run, rather than
# depending on one left over from a previous run — a short-lived test cert
# expiring mid-session caused real (spurious) failures once before.
CERT_DIR = tempfile.mkdtemp(prefix='smtptest_')
CERT_PATH = os.path.join(CERT_DIR, 'cert.pem')
KEY_PATH = os.path.join(CERT_DIR, 'key.pem')
SAN_CONF = os.path.join(CERT_DIR, 'san.cnf')
with open(SAN_CONF, 'w') as f:
    f.write('[req]\ndistinguished_name=req_distinguished_name\nx509_extensions=v3_req\nprompt=no\n'
            '[req_distinguished_name]\nCN=127.0.0.1\n[v3_req]\nsubjectAltName=IP:127.0.0.1\n')
subprocess.run(
    ['openssl', 'req', '-x509', '-newkey', 'rsa:2048', '-nodes', '-keyout', KEY_PATH,
     '-out', CERT_PATH, '-days', '365', '-config', SAN_CONF],
    capture_output=True, check=True
)

def start_server(port, out_path, extra_args=None):
    if os.path.exists(out_path):
        os.remove(out_path)
    args = ['python3', f'{ROOT}/tests/mock_smtp_server.py', str(port), out_path] + (extra_args or [])
    p = subprocess.Popen(args, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True)
    time.sleep(0.6)
    return p

def run_mailer(env_overrides, timeout=6):
    env = dict(os.environ)
    env.update({k: str(v) for k, v in env_overrides.items()})
    r = subprocess.run(['php', f'{ROOT}/tests/mailer_smtp_test.php'], env=env, capture_output=True, text=True, timeout=timeout)
    return r.stdout.strip(), r.stderr.strip()

def outbox(path):
    return [json.loads(l) for l in open(path).read().splitlines()] if os.path.exists(path) else []

print('--- plain SMTP, no auth, dot-stuffed body ---')
srv1 = start_server(2545, '/tmp/mt_plain.jsonl')
out, err = run_mailer({'T_SMTP_HOST': '127.0.0.1', 'T_SMTP_PORT': 2545, 'T_SMTP_SECURE': '',
                        'T_TO': 'officer@example.com', 'T_SUBJECT': 'URGENT: ZC-TEST-0001',
                        'T_BODY': 'Case reference: ZC-TEST-0001\n.\nSurvives the dot line.'})
check('reports SENT', out == 'SENT', (out, err))
rows = outbox('/tmp/mt_plain.jsonl')
check('server received exactly one message', len(rows) == 1, rows)
if rows:
    body = rows[0]['raw'].split('\n\n', 1)[1]
    check('dot-line correctly stuffed (doubled) and body not truncated', '..\nSurvives the dot line.' in body, repr(body))
    check('envelope MAIL FROM / RCPT TO correct', rows[0]['mail_from'] == '<safeguarding@example.org>' and rows[0]['rcpt_to'] == '<officer@example.com>', rows[0])
srv1.terminate()

print('--- STARTTLS + AUTH LOGIN: untrusted cert must be REJECTED ---')
srv2 = start_server(2546, '/tmp/mt_tls_untrusted.jsonl',
                     ['--tls', CERT_PATH, KEY_PATH, '--require-auth', 'alice', 's3cret'])
out, err = run_mailer({'T_SMTP_HOST': '127.0.0.1', 'T_SMTP_PORT': 2546, 'T_SMTP_SECURE': 'tls',
                        'T_SMTP_USER': 'alice', 'T_SMTP_PASS': 's3cret', 'T_TO': 'o@example.com',
                        'T_SUBJECT': 'x', 'T_BODY': 'x'})
check('FAILS when the server cert is not in the trust store (no MITM-vulnerable silent accept)',
      out == 'FAILED' and 'certificate verify failed' in err, (out, err))
srv2.terminate()

print('--- STARTTLS + AUTH LOGIN: trusted cert + correct creds -> succeeds, real encryption ---')
srv3 = start_server(2547, '/tmp/mt_tls_ok.jsonl',
                     ['--tls', CERT_PATH, KEY_PATH, '--require-auth', 'alice', 's3cret'])
out, err = run_mailer({'T_SMTP_HOST': '127.0.0.1', 'T_SMTP_PORT': 2547, 'T_SMTP_SECURE': 'tls',
                        'T_SMTP_USER': 'alice', 'T_SMTP_PASS': 's3cret', 'T_TO': 'officer@example.com',
                        'T_SUBJECT': 'URGENT via TLS', 'T_BODY': 'Encrypted content'},
                       )
# openssl.cafile must be set via php -d, so invoke directly here instead of run_mailer's plain php call
env = dict(os.environ); env.update({'T_SMTP_HOST': '127.0.0.1', 'T_SMTP_PORT': '2547', 'T_SMTP_SECURE': 'tls',
                                     'T_SMTP_USER': 'alice', 'T_SMTP_PASS': 's3cret', 'T_TO': 'officer@example.com',
                                     'T_SUBJECT': 'URGENT via TLS', 'T_BODY': 'Encrypted content'})
r = subprocess.run(['php', '-d', f'openssl.cafile={CERT_PATH}', f'{ROOT}/tests/mailer_smtp_test.php'],
                    env=env, capture_output=True, text=True, timeout=6)
check('reports SENT once the cert is trusted', r.stdout.strip() == 'SENT', r.stderr)
rows = outbox('/tmp/mt_tls_ok.jsonl')
check('server actually received it, over a real TLS connection', len(rows) == 1 and rows[0]['tls'] is True and rows[0]['authed'] is True, rows)
srv3.terminate()

print('--- AUTH LOGIN rejected by server -> fails cleanly, nothing delivered ---')
srv4 = start_server(2548, '/tmp/mt_authfail.jsonl', ['--require-auth', 'bob', 'right', '--reject-auth'])
out, err = run_mailer({'T_SMTP_HOST': '127.0.0.1', 'T_SMTP_PORT': 2548, 'T_SMTP_SECURE': '',
                        'T_SMTP_USER': 'bob', 'T_SMTP_PASS': 'wrong', 'T_TO': 'o@example.com',
                        'T_SUBJECT': 'x', 'T_BODY': 'x'})
check('reports FAILED, not a crash', out == 'FAILED', (out, err))
check('caught as a clean exception, not a fatal error', '535' in err and 'Fatal error' not in err, err)
check('nothing was delivered to the server', outbox('/tmp/mt_authfail.jsonl') == [])
srv4.terminate()

print('--- connection refused (no server listening) -> fails cleanly ---')
out, err = run_mailer({'T_SMTP_HOST': '127.0.0.1', 'T_SMTP_PORT': 2599, 'T_TO': 'o@example.com', 'T_SUBJECT': 'x', 'T_BODY': 'x'})
check('reports FAILED, not a crash', out == 'FAILED', (out, err))
check('connection failure logged, not a fatal PHP error', 'connect failed' in err and 'Fatal error' not in err, err)

print(f'\nRESULT: {ok} passed, {fail} failed')
