#!/usr/bin/env python3
"""
Preview + API proxy server (port 8765)
- Serves static files from ~/.openclaw/workspace/
- Proxies /api/ and /health to issues-api on port 8769
- Also serves /data/attachments/ as static files (for attachment downloads)
"""
import http.server
import urllib.request
import urllib.error
import os
import sys

PORT      = 8765
SERVE_DIR = os.path.expanduser("~/.openclaw/workspace")
API_BASE  = "http://127.0.0.1:8769"
DATA_DIR  = os.path.expanduser("~/.openclaw/workspace/data")

PROXY_PREFIXES = ('/api/', '/health')


class Handler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=SERVE_DIR, **kwargs)

    # ── Route all methods ──────────────────────────────────────────────────────
    def _route(self):
        if self.path.startswith('/data/attachments/'):
            self._serve_attachment()
        elif self.path.startswith('/api/') or self.path in ('/health', '/health/'):
            self._proxy()
        else:
            return False
        return True

    def do_GET(self):
        if not self._route():
            super().do_GET()

    def do_POST(self):
        if not self._route():
            self._method_not_allowed()

    def do_PUT(self):
        if not self._route():
            self._method_not_allowed()

    def do_DELETE(self):
        if not self._route():
            self._method_not_allowed()

    def do_OPTIONS(self):
        if not self._route():
            self._cors_ok()

    def _method_not_allowed(self):
        self.send_response(405)
        self.end_headers()

    def _cors_ok(self):
        self.send_response(204)
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        self.send_header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS')
        self.end_headers()

    # ── Static attachment serving ──────────────────────────────────────────────
    def _serve_attachment(self):
        rel   = self.path[len('/data/attachments/'):]
        parts = rel.split('/')
        if len(parts) < 2 or '..' in parts:
            self.send_response(400)
            self.end_headers()
            return
        file_path = os.path.join(DATA_DIR, 'attachments', *parts)
        if not os.path.isfile(file_path):
            self.send_response(404)
            self.end_headers()
            return
        ext  = os.path.splitext(file_path)[1].lower()
        mime = {
            '.jpg':'.jpg', '.jpeg': 'image/jpeg', '.png': 'image/png',
            '.gif': 'image/gif', '.webp': 'image/webp',
            '.pdf': 'application/pdf',
        }.get(ext, 'application/octet-stream')
        with open(file_path, 'rb') as fh:
            data = fh.read()
        self.send_response(200)
        self.send_header('Content-Type', mime)
        self.send_header('Content-Length', str(len(data)))
        self.send_header('Cache-Control', 'public, max-age=3600')
        self.end_headers()
        self.wfile.write(data)

    # ── Proxy ──────────────────────────────────────────────────────────────────
    def _proxy(self):
        target = API_BASE + self.path

        # Read body
        length = int(self.headers.get('Content-Length', 0) or 0)
        body   = self.rfile.read(length) if length > 0 else None

        # Forward relevant headers
        forward_headers = {}
        ct = self.headers.get('Content-Type')
        if ct:
            forward_headers['Content-Type'] = ct

        req = urllib.request.Request(
            target,
            data=body,
            method=self.command,
            headers=forward_headers,
        )
        try:
            with urllib.request.urlopen(req, timeout=30) as resp:
                resp_body = resp.read()
                self.send_response(resp.status)
                self.send_header('Content-Type',   resp.headers.get('Content-Type', 'application/json'))
                self.send_header('Content-Length', str(len(resp_body)))
                self.send_header('Access-Control-Allow-Origin',  '*')
                self.send_header('Access-Control-Allow-Headers', 'Content-Type')
                self.send_header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS')
                self.end_headers()
                self.wfile.write(resp_body)
        except urllib.error.HTTPError as e:
            resp_body = e.read()
            self.send_response(e.code)
            self.send_header('Content-Type',   'application/json')
            self.send_header('Content-Length', str(len(resp_body)))
            self.end_headers()
            self.wfile.write(resp_body)
        except Exception as ex:
            msg = str(ex).encode()
            self.send_response(502)
            self.send_header('Content-Type',   'text/plain')
            self.send_header('Content-Length', str(len(msg)))
            self.end_headers()
            self.wfile.write(msg)

    def log_message(self, fmt, *args):
        print(fmt % args, flush=True)


if __name__ == '__main__':
    os.chdir(SERVE_DIR)
    server = http.server.HTTPServer(('0.0.0.0', PORT), Handler)
    print(f'Preview+proxy server on :{PORT}  →  static:{SERVE_DIR}  api:{API_BASE}', flush=True)
    server.serve_forever()
