"""MVP 本地服务器：静态文件 + HTTP Range 支持（视频 seek 必需）。

用法：
  python3 server.py [端口，默认 8080]
然后浏览器打开：
  http://localhost:8080/player/?dir=outputs/<视频名>
"""
import http.server
import os
import re
import shutil
import socketserver
import sys


class RangeHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    """在 SimpleHTTPRequestHandler 基础上补 HTTP Range（206），
    让 <video> 的进度条拖拽/seek 正常工作。
    """

    def send_head(self):
        self._range = None
        path = self.translate_path(self.path)
        if os.path.isdir(path):
            return super().send_head()

        f = None
        try:
            f = open(path, "rb")
        except OSError:
            self.send_error(404, "File not found")
            return None

        try:
            fs = os.fstat(f.fileno())
            file_len = fs.st_size
            start, end = 0, file_len - 1

            rng = self.headers.get("Range")
            if rng:
                m = re.match(r"bytes=(\d+)-(\d*)", rng)
                if not m:
                    self.send_error(416, "Range Not Satisfiable")
                    return None
                start = int(m.group(1))
                end = int(m.group(2)) if m.group(2) else file_len - 1
                if start >= file_len:
                    self.send_error(416, "Range Not Satisfiable")
                    return None
                end = min(end, file_len - 1)
                self.send_response(206)
                self.send_header("Content-Range", f"bytes {start}-{end}/{file_len}")
                self.send_header("Accept-Ranges", "bytes")
                self.send_header("Content-Length", str(end - start + 1))
            else:
                self.send_response(200)
                self.send_header("Accept-Ranges", "bytes")
                self.send_header("Content-Length", str(file_len))

            self.send_header("Content-Type", self.guess_type(path))
            self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
            self.end_headers()
            f.seek(start)
            self._range = (start, end)
            return f
        except Exception:
            if f:
                f.close()
            raise

    def copyfile(self, source, outputfile):
        if self.command == "HEAD":
            return
        rng = getattr(self, "_range", None)
        if not rng:
            # 目录请求（/player/ → index.html）或未走 Range 分支：正常整文件发送
            shutil.copyfileobj(source, outputfile)
            return
        start, end = rng
        remaining = end - start + 1
        while remaining > 0:
            chunk = source.read(min(64 * 1024, remaining))
            if not chunk:
                break
            outputfile.write(chunk)
            remaining -= len(chunk)


def main():
    port = int(sys.argv[1]) if len(sys.argv) > 1 else 8080
    handler = RangeHTTPRequestHandler
    # 静态服务目录设为项目根目录，便于访问 outputs/ 与 player/
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    with socketserver.ThreadingTCPServer(("0.0.0.0", port), handler) as httpd:
        print(f"服务已启动：http://localhost:{port}/player/")
        print(f"  例：http://localhost:{port}/player/?dir=outputs/<视频名>")
        httpd.serve_forever()


if __name__ == "__main__":
    main()
