#!/usr/bin/env python3
"""GeoJSON proxy service for OpenRemote assets map display.
Fetches all assets with location from OpenRemote REST API and serves them as GeoJSON.
"""

import json
import os
import urllib.request
import urllib.error
import urllib.parse
from http.server import HTTPServer, BaseHTTPRequestHandler

OR_URL = os.environ.get("OR_URL", "http://openremote_manager_1:8080")
OR_ADMIN_USER = os.environ.get("OR_ADMIN_USER", "admin")
OR_ADMIN_PASS = os.environ.get("OR_ADMIN_PASS", "Digitribe972")
OR_REALM = os.environ.get("OR_REALM", "master")
OR_CLIENT_SECRET = os.environ.get("OR_CLIENT_SECRET", "0oQjzTfiEELYmj5jFwT4iIuWUDtQDvVa")

_token_cache = {"token": "", "expires": 0}


def get_token():
    """Fetch an OpenRemote access token using admin credentials."""
    import time
    if _token_cache["token"] and _token_cache["expires"] > time.time() + 30:
        return _token_cache["token"]
    data = urllib.parse.urlencode({
        "username": OR_ADMIN_USER,
        "password": OR_ADMIN_PASS,
        "grant_type": "password",
        "client_id": "openremote",
        "client_secret": OR_CLIENT_SECRET
    }).encode()
    req = urllib.request.Request(
        f"http://openremote-keycloak-1:8080/auth/realms/{OR_REALM}/protocol/openid-connect/token",
        data=data,
        headers={"Content-Type": "application/x-www-form-urlencoded"},
        method="POST"
    )
    resp = urllib.request.urlopen(req, timeout=10)
    body = json.loads(resp.read())
    _token_cache["token"] = body["access_token"]
    _token_cache["expires"] = time.time() + max(body.get("expires_in", 300) - 60, 30)
    return _token_cache["token"]


def fetch_assets():
    """Fetch all assets with location from OpenRemote REST API."""
    token = get_token()
    features = []

    # Query all assets with location attribute
    try:
        # Use the asset query API to get all assets with location
        query = json.dumps({
            "attributes": {
                "location": {
                    "value": {"$exists": True}
                }
            }
        }).encode()
        req = urllib.request.Request(
            f"{OR_URL}/api/{OR_REALM}/asset/query",
            data=query,
            headers={
                "Authorization": f"Bearer {token}",
                "Accept": "application/json",
                "Content-Type": "application/json"
            },
            method="POST"
        )
        with urllib.request.urlopen(req, timeout=30) as r:
            assets = json.loads(r.read().decode())
            if not isinstance(assets, list):
                assets = [assets]
    except Exception as e:
        # Fallback: try to get all assets and filter
        try:
            req = urllib.request.Request(
                f"{OR_URL}/api/{OR_REALM}/asset?limit=100",
                headers={"Authorization": f"Bearer {token}", "Accept": "application/json"}
            )
            with urllib.request.urlopen(req, timeout=30) as r:
                assets = json.loads(r.read().decode())
                if not isinstance(assets, list):
                    assets = [assets]
        except Exception as e2:
            return {"type": "FeatureCollection", "features": [], "error": str(e2)}

    for asset in assets:
        try:
            attrs = asset.get("attributes", {})
            location = attrs.get("location", {})
            value = location.get("value") if isinstance(location, dict) else None
            coords = value.get("coordinates") if isinstance(value, dict) else None
            if not coords or len(coords) < 2:
                continue

            props = {
                "id": asset.get("id"),
                "name": asset.get("name", ""),
                "type": asset.get("type", ""),
                "realm": asset.get("realm", ""),
            }
            # Add sensorType for color mapping
            sensor_type = attrs.get("sensorType", {})
            if isinstance(sensor_type, dict):
                props["sensorType"] = sensor_type.get("value", "")
            # Add scalar attribute values
            for attr_name, attr_val in attrs.items():
                if isinstance(attr_val, dict):
                    v = attr_val.get("value")
                    if v is not None and not isinstance(v, (dict, list)):
                        props[attr_name] = v

            # GeoJSON coordinates are [longitude, latitude]
            features.append({
                "type": "Feature",
                "geometry": {"type": "Point", "coordinates": [coords[1], coords[0]]},
                "properties": props
            })
        except Exception:
            continue

    return {"type": "FeatureCollection", "features": features}


class GeoJSONHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        path = self.path.split("?")[0]
        if path == "/geojson":
            try:
                result = fetch_assets()
                body = json.dumps(result).encode()
                self.send_response(200)
                self.send_header("Content-Type", "application/json")
                self.send_header("Access-Control-Allow-Origin", "*")
                self.send_header("Content-Length", str(len(body)))
                self.end_headers()
                self.wfile.write(body)
            except Exception as e:
                error_body = json.dumps({"error": str(e)}).encode()
                self.send_response(500)
                self.send_header("Content-Type", "application/json")
                self.send_header("Access-Control-Allow-Origin", "*")
                self.send_header("Content-Length", str(len(error_body)))
                self.end_headers()
                self.wfile.write(error_body)
        elif path == "/health":
            body = json.dumps({"status": "ok"}).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 log_message(self, format, *args):
        print(f"[geojson-proxy] {args[0]}")


if __name__ == "__main__":
    server = HTTPServer(("0.0.0.0", 8080), GeoJSONHandler)
    print("[geojson-proxy] Listening on 0.0.0.0:8080")
    server.serve_forever()
