#!/usr/bin/env python3
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
from pathlib import Path
import os

ROOT = Path(__file__).resolve().parent

class Handler(SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=str(ROOT), **kwargs)

    def end_headers(self):
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Range, Content-Type')
        self.send_header('Accept-Ranges', 'bytes')
        if self.path.endswith(('.mp4', '.jpg', '.jpeg', '.webp')):
            self.send_header('Cache-Control', 'public, max-age=31536000, immutable')
        super().end_headers()

    def guess_type(self, path):
        if path.endswith('.mp4'):
            return 'video/mp4'
        if path.endswith('.jpg') or path.endswith('.jpeg'):
            return 'image/jpeg'
        if path.endswith('.webp'):
            return 'image/webp'
        return super().guess_type(path)

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

    def send_head(self):
        path = self.translate_path(self.path)
        if not path.endswith('.mp4'):
            return super().send_head()
        if not os.path.exists(path):
            self.send_error(404, 'File not found')
            return None
        size = os.path.getsize(path)
        range_header = self.headers.get('Range')
        if not range_header:
            self.send_response(200)
            self.send_header('Content-type', 'video/mp4')
            self.send_header('Content-Length', str(size))
            self.send_header('Accept-Ranges', 'bytes')
            self.end_headers()
            return open(path, 'rb')
        try:
            unit, rng = range_header.split('=', 1)
            start_s, end_s = rng.split('-', 1)
            start = int(start_s) if start_s else 0
            end = int(end_s) if end_s else size - 1
            end = min(end, size - 1)
            length = end - start + 1
            f = open(path, 'rb')
            f.seek(start)
            self.range = (start, end, length)
            self.send_response(206)
            self.send_header('Content-type', 'video/mp4')
            self.send_header('Content-Range', f'bytes {start}-{end}/{size}')
            self.send_header('Content-Length', str(length))
            self.send_header('Accept-Ranges', 'bytes')
            self.end_headers()
            return f
        except Exception:
            self.send_error(416, 'Requested Range Not Satisfiable')
            return None

    def copyfile(self, source, outputfile):
        if hasattr(self, 'range'):
            remaining = self.range[2]
            while remaining > 0:
                chunk = source.read(min(64 * 1024, remaining))
                if not chunk:
                    break
                outputfile.write(chunk)
                remaining -= len(chunk)
            del self.range
        else:
            super().copyfile(source, outputfile)

if __name__ == '__main__':
    httpd = ThreadingHTTPServer(('0.0.0.0', 8840), Handler)
    print('AZUROTEC media server on :8840 with Range support')
    httpd.serve_forever()
