#!/usr/bin/env python3
"""Static file server: CORS, HTTP Range (video seeking/streaming), smart caching.
HTML and directory indexes stay no-cache (Gamma/video-slides embeds always fresh);
other assets (mp4, images, etc.) are cached for 1 day. Backward compatible.
"""
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")
        p = self.path.split("?", 1)[0]
        if p.endswith("/") or p.endswith(".html") or p.endswith(".htm"):
            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 send_head(self):
        path = self.translate_path(self.path)
        if os.path.isdir(path) or not os.path.isfile(path):
            self._range = None
            return super().send_head()
        rng = self.headers.get("Range")
        if not rng:
            self._range = None
            return super().send_head()
        m = re.match(r"bytes=(\d*)-(\d*)\s*$", rng.strip())
        if not m or (not m.group(1) and not m.group(2)):
            self._range = None
            return super().send_head()
        try:
            f = open(path, "rb")
        except OSError:
            self.send_error(404, "File not found")
            return None
        try:
            size = os.fstat(f.fileno()).st_size
            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()
                f.close()
                return None
            length = end - start + 1
            self._range = (start, length)
            self.send_response(206)
            self.send_header("Content-Type", self.guess_type(path))
            self.send_header("Content-Range", f"bytes {start}-{end}/{size}")
            self.send_header("Content-Length", str(length))
            self.end_headers()
            f.seek(start)
            return f
        except Exception:
            f.close()
            raise

    def copyfile(self, source, outputfile):
        rng = getattr(self, "_range", None)
        if not rng:
            return super().copyfile(source, outputfile)
        _start, length = rng
        remaining = length
        while remaining > 0:
            chunk = source.read(min(65536, remaining))
            if not chunk:
                break
            outputfile.write(chunk)
            remaining -= len(chunk)


os.chdir(ROOT)
http.server.ThreadingHTTPServer(("0.0.0.0", 8090), Handler).serve_forever()
