"""
Flask Web Application for Beacon Tracker Video Streaming

This application reads JPEG frames from shared memory and streams them
to web browsers via Server-Sent Events (SSE).
"""

from flask import Flask, render_template, Response, jsonify
from shared_memory_reader import SharedMemoryFrameReader
import time
import base64
import json
from threading import Lock

app = Flask(__name__)

# Global state
reader = None
reader_lock = Lock()
last_frame_data = None
last_frame_header = None
frame_lock = Lock()


def init_reader():
    """Initialize the shared memory reader"""
    global reader
    with reader_lock:
        if reader is None:
            try:
                reader = SharedMemoryFrameReader()
                print("Connected to shared memory successfully")
            except Exception as e:
                print(f"Failed to connect to shared memory: {e}")
                reader = None


@app.route('/')
def index():
    """Render the main page"""
    return render_template('index.html')


@app.route('/stream')
def stream():
    """
    Server-Sent Events stream endpoint

    Continuously sends JPEG frames to the client as they become available.
    """
    def generate():
        global reader

        # Initialize reader for this stream
        init_reader()

        # Check again after init
        with reader_lock:
            local_reader = reader

        if local_reader is None:
            yield f"data: {json.dumps({'error': 'Failed to connect to shared memory'})}\n\n"
            return

        consecutive_failures = 0
        max_failures = 100

        while True:
            try:
                with reader_lock:
                    if reader is None:
                        yield f"data: {json.dumps({'error': 'Reader is None'})}\n\n"
                        return
                    result = reader.read_frame()

                if result:
                    header, jpeg_data = result
                    consecutive_failures = 0

                    # Encode JPEG as base64 for transmission
                    jpeg_base64 = base64.b64encode(jpeg_data).decode('utf-8')

                    # Create event data
                    event_data = {
                        'frame_number': header.frame_number,
                        'timestamp_us': header.timestamp_us,
                        'width': header.width,
                        'height': header.height,
                        'data_size': header.data_size,
                        'jpeg': jpeg_base64
                    }

                    # Send as SSE event
                    yield f"data: {json.dumps(event_data)}\n\n"

                    # Update global state
                    with frame_lock:
                        global last_frame_data, last_frame_header
                        last_frame_data = jpeg_data
                        last_frame_header = header

                else:
                    consecutive_failures += 1
                    if consecutive_failures >= max_failures:
                        yield f"data: {json.dumps({'error': 'No frames available'})}\n\n"
                        consecutive_failures = 0

                # Small delay to prevent busy waiting
                time.sleep(0.001)  # 1ms - fast updates

            except GeneratorExit:
                # Client disconnected
                break
            except Exception as e:
                print(f"Error in stream: {e}")
                yield f"data: {json.dumps({'error': str(e)})}\n\n"
                time.sleep(1)

    return Response(generate(), mimetype='text/event-stream')


@app.route('/status')
def status():
    """Get the current status of the stream"""
    init_reader()

    with frame_lock:
        if last_frame_header:
            return jsonify({
                'connected': True,
                'last_frame': last_frame_header.frame_number,
                'timestamp_us': last_frame_header.timestamp_us,
                'resolution': f"{last_frame_header.width}x{last_frame_header.height}"
            })
        else:
            return jsonify({
                'connected': reader is not None,
                'last_frame': None,
                'message': 'Waiting for frames...'
            })


@app.route('/latest_frame')
def latest_frame():
    """Get the latest frame as a JPEG image"""
    with frame_lock:
        if last_frame_data:
            return Response(last_frame_data, mimetype='image/jpeg')
        else:
            return "No frame available", 404


@app.teardown_appcontext
def cleanup(exception=None):
    """Clean up resources on shutdown"""
    global reader
    with reader_lock:
        if reader:
            reader.close()
            reader = None


if __name__ == '__main__':
    # Initialize reader on startup
    init_reader()

    # Run the Flask app
    # Use 0.0.0.0 to make it accessible from other machines on the network
    app.run(host='0.0.0.0', port=5000, debug=True, threaded=True)
