"""
Vision HTTP server for xiaozhi-esp32 camera.take_photo tool.
Uses only stdlib — no FastAPI version conflicts.

ESP32 POSTs multipart/form-data with:
  - question: str
  - file: JPEG bytes (field name varies)
"""

import os
import base64
import json
import urllib.request
import urllib.error
import logging
import email
import email.parser
import cgi
import io
from http.server import BaseHTTPRequestHandler, HTTPServer
from dotenv import load_dotenv

load_dotenv(os.path.join(os.path.dirname(__file__), ".env"))

MINIMAX_API_KEY = os.getenv("MINIMAX_API_KEY", "").strip()
PORT = int(os.getenv("VISION_PORT", "8766"))

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger("vision_server")


def analyze_with_minimax(image_bytes: bytes, question: str) -> str:
    image_b64 = base64.b64encode(image_bytes).decode()
    payload = json.dumps({
        "model": "MiniMax-M3",
        "messages": [{
            "role": "user",
            "content": [
                {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image_b64}"}},
                {"type": "text", "text": question},
            ],
        }],
        "max_tokens": 1024,
    }).encode()
    req = urllib.request.Request(
        "https://api.minimax.chat/v1/chat/completions",
        data=payload,
        headers={
            "Authorization": f"Bearer {MINIMAX_API_KEY}",
            "Content-Type": "application/json",
        },
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        result = json.loads(resp.read().decode())
    return result["choices"][0]["message"]["content"]


class VisionHandler(BaseHTTPRequestHandler):
    def log_message(self, format, *args):
        logger.info("%s - %s", self.address_string(), format % args)

    def do_GET(self):
        if self.path == "/health":
            body = json.dumps({"status": "ok", "minimax_configured": bool(MINIMAX_API_KEY)}).encode()
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)
        else:
            self.send_response(404)
            self.end_headers()

    def do_POST(self):
        if self.path != "/vision":
            self.send_response(404)
            self.end_headers()
            return

        content_type = self.headers.get("Content-Type", "")
        content_length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(content_length)

        logger.info("POST /vision content-type=%s body_size=%d", content_type, len(body))

        try:
            # Parse multipart/form-data
            environ = {"REQUEST_METHOD": "POST", "CONTENT_TYPE": content_type}
            fs = cgi.FieldStorage(
                fp=io.BytesIO(body),
                headers=self.headers,
                environ=environ,
            )

            question = "请描述这张图片里有什么"
            if "question" in fs:
                question = fs["question"].value
                logger.info("question: %s", question)

            image_bytes = None
            # The file field might be named "file", "image", or anything else
            for key in fs.keys():
                field = fs[key]
                if hasattr(field, "filename") and field.filename:
                    image_bytes = field.file.read()
                    logger.info("image field=%s filename=%s size=%d", key, field.filename, len(image_bytes))
                    break

            if not image_bytes:
                self._json_response(400, {"error": "no image file in request"})
                return

            answer = analyze_with_minimax(image_bytes, question)
            logger.info("MiniMax answer length: %d", len(answer))
            self._json_response(200, {"result": answer})

        except urllib.error.HTTPError as e:
            err = e.read().decode()[:300]
            logger.error("MiniMax API error: %s %s", e.code, err)
            self._json_response(502, {"error": f"MiniMax error {e.code}: {err}"})
        except Exception as e:
            logger.error("vision error: %s", e, exc_info=True)
            self._json_response(500, {"error": str(e)})

    def _json_response(self, status: int, data: dict):
        body = json.dumps(data, ensure_ascii=False).encode()
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


if __name__ == "__main__":
    server = HTTPServer(("0.0.0.0", PORT), VisionHandler)
    logger.info("Vision server listening on port %d", PORT)
    server.serve_forever()
