#!/usr/bin/env python3
"""Static file server: CORS, HTTP Range (video seeking/streaming), smart caching.
- *.html and directory index -> no-cache (keeps Gamma/video-slides embeds fresh)
- other assets (mp4, jpg, png, ...) -> public, max-age=86400
- Range requests -> 206 Partial Content (video seeking + progressive load)
"""
import http.server
import os
import re

ROOT = '/opt/static-assets'

class Handler(http.server.SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS')
        self.send_header('Accept-Ranges', 'bytes')
        clean = self.path.split('?', 1)[0]
        if clean.endswith('.html') or clean.endswith('/'):
            self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Expires', '0')
        else:
            self.send_header('Cache-Control', 'public, max-age=86400')
        super().end_headers()

    def do_OPTIONS(self):
        self.send_response(204)
        self.end_headers()

    def do_HEAD(self):
        self._serve(False)

    def do_GET(self):
        self._serve(True)

    def _serve(self, body):
        path = self.translate_path(self.path)
        if os.path.isdir(path):
            f = super().send_head()
            if f:
                try:
                    if body:
                        self.copyfile(f, self.wfile)
                finally:
                    f.close()
            return
        try:
            f = open(path, 'rb')
        except OSError:
            self.send_error(404, "File not found")
            return
        try:
            size = os.fstat(f.fileno()).st_size
            ctype = self.guess_type(path)
            rangeh = self.headers.get('Range')
            if rangeh:
                m = re.match(r'bytes=(\d*)-(\d*)\s*$', rangeh.strip())
                if m and (m.group(1) or m.group(2)):
                    if m.group(1):
                        start = int(m.group(1))
                        end = int(m.group(2)) if m.group(2) else size - 1
                    else:
                        start = max(0, size - int(m.group(2)))
                        end = size - 1
                    end = min(end, size - 1)
                    if start > end or start >= size:
                        self.send_response(416)
                        self.send_header('Content-Range', f'bytes */{size}')
                        self.end_headers()
                        return
                    self.send_response(206)
                    self.send_header('Content-Type', ctype)
                    self.send_header('Content-Range', f'bytes {start}-{end}/{size}')
                    self.send_header('Content-Length', str(end - start + 1))
                    self.end_headers()
                    if body:
                        f.seek(start)
                        rem = end - start + 1
                        while rem > 0:
                            chunk = f.read(min(262144, rem))
                            if not chunk:
                                break
                            try:
                                self.wfile.write(chunk)
                            except (BrokenPipeError, ConnectionResetError):
                                break
                            rem -= len(chunk)
                    return
            self.send_response(200)
            self.send_header('Content-Type', ctype)
            self.send_header('Content-Length', str(size))
            self.end_headers()
            if body:
                try:
                    self.copyfile(f, self.wfile)
                except (BrokenPipeError, ConnectionResetError):
                    pass
        finally:
            f.close()

os.chdir(ROOT)
print('Static assets server running on :8090 (CORS, Range, smart-cache)')
http.server.ThreadingHTTPServer(('0.0.0.0', 8090), Handler).serve_forever()
