from __future__ import annotations

import json
import math
from pathlib import Path

import mapbox_vector_tile


INPUT_ROOT = Path("/home/wwwroot/newpec/exported_auto/tile.mapple-on.jp__newpec-mvt-20260106__z___x___y_.pbf/tiles")
OUTPUT_ROOT = Path("/home/wwwroot/newpec/exported_auto/geojson_linux")


def tile_coord_to_lonlat(z: int, x: int, y: int, tx: float, ty: float, extent: int) -> list[float]:
    lon = ((x + (tx / extent)) / (2**z)) * 360.0 - 180.0
    lat = math.degrees(
        math.atan(
            math.sinh(
                math.pi * (1.0 - (2.0 * (y + (ty / extent)) / (2**z)))
            )
        )
    )
    return [lon, lat]


def convert_geometry(geometry: dict, z: int, x: int, y: int, extent: int) -> dict:
    geom_type = geometry["type"]
    coords = geometry["coordinates"]

    if geom_type == "Point":
        return {"type": "Point", "coordinates": tile_coord_to_lonlat(z, x, y, coords[0], coords[1], extent)}
    if geom_type == "MultiPoint":
        return {
            "type": "MultiPoint",
            "coordinates": [tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in coords],
        }
    if geom_type == "LineString":
        return {
            "type": "LineString",
            "coordinates": [tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in coords],
        }
    if geom_type == "MultiLineString":
        return {
            "type": "MultiLineString",
            "coordinates": [
                [tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in line]
                for line in coords
            ],
        }
    if geom_type == "Polygon":
        return {
            "type": "Polygon",
            "coordinates": [
                [tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in ring]
                for ring in coords
            ],
        }
    if geom_type == "MultiPolygon":
        return {
            "type": "MultiPolygon",
            "coordinates": [
                [
                    [tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in ring]
                    for ring in polygon
                ]
                for polygon in coords
            ],
        }
    raise RuntimeError(f"unsupported geometry type: {geom_type}")


def convert_tile(path: Path) -> tuple[dict, int]:
    z = int(path.parent.parent.name)
    x = int(path.parent.name)
    y = int(path.stem)

    with path.open("rb") as fh:
        decoded = mapbox_vector_tile.decode(fh.read())

    features = []
    for vt_layer, payload in decoded.items():
        extent = int(payload.get("extent") or 4096)
        for feature in payload.get("features", []):
            properties = dict(feature.get("properties") or {})
            properties["vt_layer"] = vt_layer
            out_feature = {
                "type": "Feature",
                "geometry": convert_geometry(feature["geometry"], z, x, y, extent),
                "properties": properties,
            }
            if feature.get("id") is not None:
                out_feature["id"] = feature["id"]
            features.append(out_feature)

    return {"type": "FeatureCollection", "features": features}, len(features)


def main() -> None:
    OUTPUT_ROOT.mkdir(parents=True, exist_ok=True)
    tile_paths = sorted(INPUT_ROOT.glob("*/*/*.pbf"))
    total_features = 0

    for index, path in enumerate(tile_paths, start=1):
        collection, count = convert_tile(path)
        total_features += count
        output_path = OUTPUT_ROOT / f"{path.parent.parent.name}_{path.parent.name}_{path.stem}.json"
        output_path.write_text(
            json.dumps(collection, ensure_ascii=False, separators=(",", ":")),
            encoding="utf-8",
        )
        if index % 5000 == 0:
            print(f"processed {index}/{len(tile_paths)} tiles, wrote {total_features} features")

    print(f"Converted {len(tile_paths)} tiles into {OUTPUT_ROOT} with {total_features} features")


if __name__ == "__main__":
    main()
