#!/usr/bin/env python3
import http.server, json, threading, tempfile, os, sys
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError

class Sink(http.server.BaseHTTPRequestHandler):
    mode = 'success'
    received = 0
    def do_POST(self):
        if self.mode == 'success':
            n = int(self.headers.get('Content-Length','0')); self.rfile.read(n)
            type(self).received += 1
            self.send_response(204); self.end_headers()
        else:
            self.send_error(503, 'injected failure')
    def log_message(self, *args): pass

def run_delivery(url, state_path):
    req = Request(url, data=b'{"event":"demo"}', method='POST', headers={'Content-Type':'application/json'})
    try:
        with urlopen(req, timeout=2) as r:
            if r.status != 204: return False, f'http_{r.status}'
        with open(state_path, 'w') as f: json.dump({'delivered': True}, f)
        return True, 'delivered'
    except (URLError, HTTPError, TimeoutError) as e:
        return False, type(e).__name__

def main():
    server = http.server.ThreadingHTTPServer(('127.0.0.1', 0), Sink)
    t = threading.Thread(target=server.serve_forever, daemon=True); t.start()
    url = f'http://127.0.0.1:{server.server_port}/hook'
    with tempfile.TemporaryDirectory() as d:
        state = os.path.join(d, 'state.json')
        # Success must be reachable and advance state only after 204.
        Sink.mode = 'success'; Sink.received = 0
        ok, why = run_delivery(url, state)
        assert ok and why == 'delivered' and Sink.received == 1, (ok, why, Sink.received)
        assert json.load(open(state))['delivered'] is True
        # Failure must not advance/overwrite state.
        os.unlink(state); Sink.mode = 'failure'; Sink.received = 0
        ok, why = run_delivery(url, state)
        assert not ok and not os.path.exists(state) and Sink.received == 0, (ok, why, os.path.exists(state), Sink.received)
        # Fixture guard: configuration with no reachable sink is invalid, not a passing recovery case.
        bad_ok, _ = run_delivery('http://127.0.0.1:1/unreachable', state)
        assert not bad_ok and not os.path.exists(state)
    server.shutdown(); server.server_close()
    print('PASS success: 204 accepted, delivery state advanced after response')
    print('PASS injected failure: non-success returned, state unchanged')
    print('PASS invalid fixture guard: unreachable sink is not treated as success')

if __name__ == '__main__':
    main()
