"""
FreeExile Cocos Creator Web Preview Server.
Serves client/cocos/preview-template/ on port 8088 (or custom port).
Includes full backend parity: /api/feedback and /api/map endpoints.
"""

import http.server
import json
import os
from pathlib import Path
import socket
import socketserver
import sys
import urllib.parse

if hasattr(sys.stdout, 'reconfigure'):
    sys.stdout.reconfigure(encoding='utf-8')

PROJECT_ROOT = Path(__file__).resolve().parent.parent
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

try:
    from server.feedback.feedback_service import FeedbackService, SystemDiagnosticsDTO
except ImportError:
    FeedbackService = None  # type: ignore
    SystemDiagnosticsDTO = None  # type: ignore

try:
    from server.world.wilderness_map_generator import WildernessMapGenerator
    from server.world.map_binary_serializer import serialize_map_grid
except ImportError:
    WildernessMapGenerator = None  # type: ignore
    serialize_map_grid = None  # type: ignore

PREVIEW_DIR = PROJECT_ROOT / "client" / "cocos" / "preview-template"


class CocosPreviewHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    extensions_map = http.server.SimpleHTTPRequestHandler.extensions_map.copy()
    extensions_map.update({
        ".js": "application/javascript",
        ".mjs": "application/javascript",
        ".css": "text/css",
        ".html": "text/html; charset=utf-8",
        ".json": "application/json",
        ".png": "image/png",
        ".jpg": "image/jpeg",
        ".astc": "application/octet-stream",
    })

    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=str(PREVIEW_DIR), **kwargs)

    def end_headers(self):
        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
        self.send_header("Access-Control-Allow-Headers", "Content-Type")
        self.send_header("Cache-Control", "no-cache, no-store, must-revalidate")
        super().end_headers()

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

    def do_POST(self):
        if self.path == "/api/feedback":
            try:
                content_length = int(self.headers.get("Content-Length", 0))
                body = self.rfile.read(content_length)
                data = json.loads(body.decode("utf-8"))

                diag_data = data.get("diagnostics", {})
                diag = None
                if SystemDiagnosticsDTO:
                    diag = SystemDiagnosticsDTO(
                        client_platform=diag_data.get("client_platform", "Cocos-Web"),
                        os_version=diag_data.get("os_version", "Windows / Web Preview"),
                        device_model=diag_data.get("device_model", "Desktop Simulator"),
                        current_fps=float(diag_data.get("current_fps", 120.0)),
                        current_ping_ms=int(diag_data.get("current_ping_ms", 18)),
                        current_zone_name=diag_data.get("current_zone_name", "Doanh Trại Bến Lưu Đày"),
                        player_x=float(diag_data.get("player_x", 0.0)),
                        player_y=float(diag_data.get("player_y", 0.0)),
                        player_z=float(diag_data.get("player_z", 0.0)),
                        game_build_version=diag_data.get("game_build_version", "Cocos-3.8-Preview")
                    )

                if FeedbackService:
                    feedback_service = FeedbackService()
                    success, fb_id, msg = feedback_service.submit_feedback(
                        player_id=int(data.get("player_id", 10001)),
                        player_name=str(data.get("player_name", "Vô Danh Lãng Khách")),
                        category=str(data.get("category", "GAMEPLAY_SUGGESTION")),
                        title=str(data.get("title", "")),
                        content=str(data.get("content", "")),
                        diagnostics=diag
                    )
                else:
                    success, fb_id, msg = False, "", "Feedback service not available on server"

                res_data = {"success": success, "feedback_id": fb_id, "message": msg}
                res_bytes = json.dumps(res_data, ensure_ascii=False).encode("utf-8")
                self.send_response(200 if success else 400)
                self.send_header("Content-Type", "application/json; charset=utf-8")
                self.send_header("Content-Length", str(len(res_bytes)))
                self.end_headers()
                self.wfile.write(res_bytes)
            except Exception as e:
                err_bytes = json.dumps({"success": False, "error": str(e)}).encode("utf-8")
                self.send_response(500)
                self.send_header("Content-Type", "application/json; charset=utf-8")
                self.send_header("Content-Length", str(len(err_bytes)))
                self.end_headers()
                self.wfile.write(err_bytes)
        else:
            self.send_error(404, "Endpoint not found")

    def do_GET(self):
        if self.path.startswith("/api/feedback"):
            try:
                if FeedbackService:
                    feedback_service = FeedbackService()
                    feedbacks = feedback_service.list_feedbacks(limit=20)
                    records = [
                        {
                            "feedback_id": f.feedback_id,
                            "player_id": f.player_id,
                            "player_name": f.player_name,
                            "category": f.category,
                            "title": f.title,
                            "content": f.content,
                            "status": f.status,
                            "admin_response": f.admin_response,
                            "created_at_ms": f.created_at_ms
                        }
                        for f in feedbacks
                    ]
                else:
                    records = []
                res_bytes = json.dumps({"feedbacks": records}, ensure_ascii=False).encode("utf-8")
                self.send_response(200)
                self.send_header("Content-Type", "application/json; charset=utf-8")
                self.send_header("Content-Length", str(len(res_bytes)))
                self.end_headers()
                self.wfile.write(res_bytes)
            except Exception as e:
                err_bytes = json.dumps({"error": str(e)}).encode("utf-8")
                self.send_response(500)
                self.send_header("Content-Type", "application/json; charset=utf-8")
                self.send_header("Content-Length", str(len(err_bytes)))
                self.end_headers()
                self.wfile.write(err_bytes)
        elif self.path.startswith("/api/map"):
            try:
                parsed = urllib.parse.urlparse(self.path)
                params = urllib.parse.parse_qs(parsed.query)
                zone_id = params.get("zone_id", ["zone_tang_kiem_nhai"])[0]
                seed = int(params.get("seed", [42])[0])
                biome_param = params.get("biome", [None])[0]
                if WildernessMapGenerator and serialize_map_grid:
                    gen = WildernessMapGenerator.for_zone(zone_id, biome_id=biome_param)
                    grid_data = gen.generate(seed=seed, zone_id=zone_id)
                    binary_payload = serialize_map_grid(grid_data)
                    self.send_response(200)
                    self.send_header("Content-Type", "application/octet-stream")
                    self.send_header("Content-Length", str(len(binary_payload)))
                    self.end_headers()
                    self.wfile.write(binary_payload)
                else:
                    self.send_error(500, "WildernessMapGenerator not available")
            except Exception as e:
                err_bytes = json.dumps({"error": str(e)}).encode("utf-8")
                self.send_response(500)
                self.send_header("Content-Type", "application/json; charset=utf-8")
                self.send_header("Content-Length", str(len(err_bytes)))
                self.end_headers()
                self.wfile.write(err_bytes)
        else:
            super().do_GET()


def start_server(port: int = 8088):
    print(f"[Cocos Preview Server] Serving {PREVIEW_DIR} on port {port}...")
    class ThreadingHTTPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
        daemon_threads = True
        allow_reuse_address = True
        request_queue_size = 64

    with ThreadingHTTPServer(("0.0.0.0", port), CocosPreviewHTTPRequestHandler) as httpd:
        try:
            httpd.serve_forever()
        except KeyboardInterrupt:
            print("\n[!] Server stopped cleanly.")
        except Exception as e:
            print(f"\n[!] Server error: {e}", file=sys.stderr)


if __name__ == "__main__":
    port = 8088
    if len(sys.argv) > 1 and sys.argv[1] == "--port" and len(sys.argv) > 2:
        port = int(sys.argv[2])
    start_server(port)
