import json
from http.server import BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs

import fiona
from shapely.geometry import shape, mapping

from geo.server.templates import MAP_HTML

MAX_FEATURES = 5000


def make_handler(dataset_path: str):
    """Create an HTTP request handler class bound to a dataset path."""

    class GeoHandler(BaseHTTPRequestHandler):

        def do_GET(self):
            parsed = urlparse(self.path)
            path = parsed.path

            if path == "/":
                self._send_html(MAP_HTML)
            elif path == "/api/bounds":
                self._handle_bounds()
            elif path == "/api/features":
                params = parse_qs(parsed.query)
                self._handle_features(params)
            elif path == "/api/info":
                self._handle_info()
            else:
                self.send_error(404)

        def _handle_bounds(self):
            with fiona.open(dataset_path) as src:
                bounds = list(src.bounds)
            self._send_json({"bounds": bounds})

        def _handle_features(self, params):
            bbox = None
            if "bbox" in params:
                try:
                    parts = params["bbox"][0].split(",")
                    bbox = tuple(float(p) for p in parts)
                except (ValueError, IndexError):
                    pass

            features = []
            truncated = False
            with fiona.open(dataset_path) as src:
                if bbox:
                    iterator = src.filter(bbox=bbox)
                else:
                    iterator = iter(src)

                for feature in iterator:
                    if len(features) >= MAX_FEATURES:
                        truncated = True
                        break
                    features.append({
                        "type": "Feature",
                        "properties": dict(feature.get("properties", {})),
                        "geometry": mapping(shape(feature["geometry"])),
                    })

            fc = {
                "type": "FeatureCollection",
                "features": features,
                "truncated": truncated,
            }
            self._send_json(fc)

        def _handle_info(self):
            with fiona.open(dataset_path) as src:
                crs_epsg = src.crs.to_epsg() if src.crs else None
                info = {
                    "driver": src.driver,
                    "crs": f"EPSG:{crs_epsg}" if crs_epsg else str(src.crs),
                    "geometry_type": src.schema["geometry"],
                    "feature_count": len(src),
                    "bounds": list(src.bounds),
                    "fields": {
                        name: dtype
                        for name, dtype in src.schema["properties"].items()
                    },
                }
            self._send_json(info)

        def _send_html(self, content):
            self.send_response(200)
            self.send_header("Content-Type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(content.encode("utf-8"))

        def _send_json(self, data):
            body = json.dumps(data)
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.send_header("Access-Control-Allow-Origin", "*")
            self.end_headers()
            self.wfile.write(body.encode("utf-8"))

        def log_message(self, format, *args):
            # Suppress default request logging
            pass

    return GeoHandler
