"""
FreeExile Mobile WebApp Local Testing Server.
Allows testing the 2.5D Mobile MMORPG on local smartphones (iPhone/Android)
over Wi-Fi without requiring a Mac hardware setup or an Apple Developer account.
"""

import http.server
import socket
import socketserver
import sys
import os
from pathlib import Path

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

WEBAPP_DIR = Path(__file__).resolve().parent.parent / "client" / "webapp"


import json
import subprocess
import shutil

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


def get_local_ip() -> str:
    """Detects local LAN IPv4 address for mobile device connection over Wi-Fi."""
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
    except Exception:
        ip = "127.0.0.1"
    finally:
        s.close()
    return ip


def get_tailscale_ip() -> str:
    """Detects Tailscale IPv4 address if Tailscale is installed and running."""
    tailscale_bin = shutil.which("tailscale")
    if not tailscale_bin:
        return ""
    try:
        res = subprocess.run([tailscale_bin, "ip", "-4"], capture_output=True, text=True, timeout=2)
        if res.returncode == 0 and res.stdout.strip():
            return res.stdout.strip().splitlines()[0]
    except Exception:
        pass
    return ""


class FreeExileHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=str(WEBAPP_DIR), **kwargs)

    def end_headers(self):
        # Enable PWA caching, cross-origin isolation, and no-cache during dev
        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", "iOS"),
                        os_version=diag_data.get("os_version", "iOS 18.2"),
                        device_model=diag_data.get("device_model", "iPhone 16 Pro Max"),
                        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", "Cổ Trấn Huyết Lân"),
                        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", "v2.0-Authoritative")
                    )

                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:
                import urllib.parse
                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.send_header("Access-Control-Allow-Origin", "*")
                    self.send_header("Cache-Control", "no-cache")
                    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:
            try:
                super().do_GET()
            except (ConnectionResetError, BrokenPipeError):
                pass
            except Exception as e:
                print(f"[FreeExileHTTPRequestHandler] GET error: {e}", file=sys.stderr)


def start_server(port: int = 8088):
    local_ip = get_local_ip()
    ts_ip = get_tailscale_ip()
    print("=" * 65)
    print("   FREEEXILE: MOBILE NATIVE WEBAPP TESTING SERVER")
    print("   (Test on iPhone / Android via Wi-Fi or Tailscale)")
    print("=" * 65)
    print(f"\n[+] Local Browser URL   : http://localhost:{port}/index.html")
    print(f"[+] Phone Local Wi-Fi   : http://{local_ip}:{port}/index.html")
    if ts_ip:
        print(f"[+] Phone via Tailscale : http://{ts_ip}:{port}/index.html (hoặc http://ds1:{port}/index.html)")
    print("\nInstructions for iOS (iPhone 12 Pro Max):")
    print("  1. Ensure Tailscale VPN is CONNECTED on your iPhone.")
    if ts_ip:
        print(f"  2. Open Safari on iPhone and browse to: http://{ts_ip}:{port}/index.html")
    else:
        print(f"  2. Open Safari on iPhone and browse to: http://{local_ip}:{port}/index.html")
    print("  3. Tap 'Share' (icon vuông có mũi tên) -> 'Thêm vào MH chính' (Add to Home Screen).")
    try:
        from server.gateway.ws_gateway_bridge import get_bridge_instance
        ws_bridge = get_bridge_instance(host="0.0.0.0", port=8080)
        ws_bridge.start_background()
        print(f"[+] WebSocket Gateway   : ws://localhost:8080 (Bridge active)")
    except Exception as e:
        print(f"[!] WebSocket Bridge not started: {e}")

    print("Press Ctrl+C to stop the server.")

    class ThreadingHTTPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
        daemon_threads = True
        allow_reuse_address = True
        request_queue_size = 64

    with ThreadingHTTPServer(("0.0.0.0", port), FreeExileHTTPRequestHandler) 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:
        if sys.argv[1] == "--port" and len(sys.argv) > 2:
            port = int(sys.argv[2])
        elif "--port" in sys.argv:
            idx = sys.argv.index("--port")
            if idx + 1 < len(sys.argv):
                port = int(sys.argv[idx + 1])
        else:
            try:
                port = int(sys.argv[1])
            except ValueError:
                port = 8088
    start_server(port)

