#!/usr/bin/env python3
"""Servidor estático con soporte HTTP Range (reanudar descargas) - solo loopback."""
import http.server
import os
import re
import socketserver

ROOT = os.path.expanduser("~/.funnel-share")
PORT = 8444


class RangeHandler(http.server.SimpleHTTPRequestHandler):
    def send_head(self):
        path = self.translate_path(self.path)
        if os.path.isdir(path):
            return super().send_head()
        try:
            f = open(path, "rb")
        except OSError:
            self.send_error(404, "File not found")
            return None
        try:
            fs = os.fstat(f.fileno())
            size = fs.st_size
            m = re.match(r"bytes=(\d*)-(\d*)$", self.headers.get("Range", "") or "")
            if m:
                start = int(m.group(1)) if m.group(1) else 0
                end = int(m.group(2)) if m.group(2) else size - 1
                end = min(end, size - 1)
                if start > end or start >= size:
                    self.send_error(416, "Requested Range Not Satisfiable")
                    f.close()
                    return None
                self.send_response(206)
                self.send_header("Content-Range", f"bytes {start}-{end}/{size}")
                self.send_header("Accept-Ranges", "bytes")
                self.send_header("Content-Length", str(end - start + 1))
                self.send_header("Content-Type", self.guess_type(path))
                self.end_headers()
                f.seek(start)
                self._range_remaining = end - start + 1
                return _RangeFile(f, end - start + 1)
            self.send_response(200)
            self.send_header("Accept-Ranges", "bytes")
            self.send_header("Content-Length", str(size))
            self.send_header("Content-Type", self.guess_type(path))
            self.end_headers()
            return f
        except Exception:
            f.close()
            raise

    def copyfile(self, source, outputfile):
        if isinstance(source, _RangeFile):
            remaining = source.remaining
            while remaining > 0:
                chunk = source.read(min(1024 * 1024, remaining))
                if not chunk:
                    break
                outputfile.write(chunk)
                remaining -= len(chunk)
            source.close()
        else:
            super().copyfile(source, outputfile)

    def log_message(self, fmt, *args):
        pass


class _RangeFile:
    def __init__(self, f, remaining):
        self.f = f
        self.remaining = remaining

    def read(self, n):
        return self.f.read(n)

    def close(self):
        self.f.close()


class Server(socketserver.ThreadingMixIn, http.server.HTTPServer):
    daemon_threads = True
    allow_reuse_address = True


if __name__ == "__main__":
    os.chdir(ROOT)
    with Server(("127.0.0.1", PORT), RangeHandler) as httpd:
        httpd.serve_forever()
