import threading, time
from flask import Flask, request, jsonify, abort

app = Flask(__name__)
items = {}
next_id = 1
jobs = {}

@app.get('/health')
def health():
    return {'ok': True}

@app.post('/items')
def create_item():
    global next_id
    data = request.get_json(silent=True) or {}
    name = data.get('name', '')
    if len(name) > 64:
        abort(500, 'simulated parser failure')
    item = {'id': next_id, 'name': name, 'qty': int(data.get('qty', 0))}
    items[next_id] = item
    next_id += 1
    return jsonify(item), 201

@app.get('/items/<int:item_id>')
def get_item(item_id):
    if item_id not in items:
        abort(404)
    return jsonify(items[item_id])

@app.delete('/items/<int:item_id>')
def delete_item(item_id):
    if request.headers.get('X-Admin') != 'true':
        abort(403)
    if item_id not in items:
        abort(404)
    del items[item_id]
    return '', 204

# Async work: the request "succeeds" and the failure happens later, off the request path.
@app.post('/items/<int:item_id>/export')
def export_item(item_id):
    if item_id not in items:
        abort(404)
    def work(snapshot):
        time.sleep(0.5)
        if snapshot['qty'] < 0:
            print(f"EXPORT WORKER CRASH: negative qty for item {snapshot['id']}", flush=True)
            raise ValueError('negative qty')
        print(f"export ok for item {snapshot['id']}", flush=True)
    threading.Thread(target=work, args=(dict(items[item_id]),), daemon=True).start()
    return {'queued': True}, 202

# Undocumented route: exists in the code, missing from openapi.yaml (a stale spec).
@app.get('/internal/debug')
def debug_dump():
    return jsonify({'items': items, 'env': 'lab'})

# Waitress, not app.run(): Flask's dev server sends 'Connection: close', so every
# request burns a fresh client port and a fast fuzzer exhausts them in ~30 seconds.
from waitress import serve
serve(app, host='0.0.0.0', port=5000, threads=8)
