"""
Advanced WFS probing - BBOX with correct CRS, cross-workspace layers,
and deep property inspection of the richest layers.
"""

import json
import os
import sys
import time
from datetime import datetime

import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
sys.stdout.reconfigure(encoding="utf-8")

BASE_URL = "https://ymspace.ga.nycu.edu.tw:8080/geoserver/wfs"
OUTPUT_DIR = r"C:\Users\thc1006\Desktop\NQSD\新增資料夾\data\ymmap_archive\wfs_cql_queries"


def wfs_get(params, timeout=30):
    default = {"service": "WFS", "version": "1.1.0"}
    default.update(params)
    try:
        r = requests.get(BASE_URL, params=default, verify=False, timeout=timeout)
        return r
    except Exception as e:
        print(f"  [ERROR] {e}")
        return None


def get_json(type_name, extra_params=None, timeout=60):
    params = {
        "request": "GetFeature",
        "typeName": type_name,
        "outputFormat": "application/json",
    }
    if extra_params:
        params.update(extra_params)
    r = wfs_get(params, timeout=timeout)
    if r and r.status_code == 200:
        try:
            return r.json()
        except:
            return {"error": "non-json", "text": r.text[:500]}
    elif r:
        return {"error": f"HTTP {r.status_code}", "text": r.text[:500]}
    return None


def save_json(data, filename):
    fpath = os.path.join(OUTPUT_DIR, filename)
    with open(fpath, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    return fpath


print("=" * 70)
print("Advanced WFS Probing")
print(f"Started: {datetime.now().isoformat()}")
print("=" * 70)

# ============================================================
# Part 1: Look at actual coordinate extents from building_geom
# ============================================================
print("\n--- Part 1: Determine actual coordinate system from building data ---")

# Get a sample building to see coordinate values
data = get_json("gis:gis_building_geom", {"maxFeatures": "3"})
if data and "features" in data:
    for feat in data["features"]:
        name = feat["properties"].get("BuildName", "?")
        geom = feat.get("geometry", {})
        gtype = geom.get("type", "?")
        # Get a sample coordinate
        coords = geom.get("coordinates", [])
        if gtype == "MultiPolygon" and coords:
            sample = coords[0][0][0] if coords[0] and coords[0][0] else None
            print(f"  {name}: type={gtype}, sample_coord={sample}")
        elif gtype == "Polygon" and coords:
            sample = coords[0][0] if coords[0] else None
            print(f"  {name}: type={gtype}, sample_coord={sample}")

    # Get CRS info
    crs = data.get("crs", {})
    print(f"  CRS info: {crs}")

# Also check campus boundaries for coordinate extent
data_campus = get_json("gis:gis_campus")
if data_campus and "features" in data_campus:
    print("\n  Campus boundaries:")
    for feat in data_campus["features"]:
        props = feat["properties"]
        name = props.get("NAME_CH", "?")
        area = props.get("area", "?")
        geom = feat.get("geometry", {})
        if geom.get("coordinates"):
            coords_flat = []
            def flatten_coords(c):
                if isinstance(c[0], (int, float)):
                    coords_flat.append(c)
                else:
                    for sub in c:
                        flatten_coords(sub)
            flatten_coords(geom["coordinates"])
            if coords_flat:
                xs = [c[0] for c in coords_flat]
                ys = [c[1] for c in coords_flat]
                print(f"  {name}: area={area}")
                print(f"    X range: {min(xs):.6f} - {max(xs):.6f}")
                print(f"    Y range: {min(ys):.6f} - {max(ys):.6f}")

# ============================================================
# Part 2: Deep inspection of gis_building (richest layer: 41 columns)
# ============================================================
print("\n--- Part 2: Deep inspection of gis:gis_building (41 properties) ---")

data_bldg = get_json("gis:gis_building")
if data_bldg and "features" in data_bldg:
    save_json(data_bldg, "gis_gis_building_FULL_PROPERTIES.json")
    print(f"  Saved full building data with all 41 properties")
    print(f"  Total buildings: {len(data_bldg['features'])}")

    # Analyze which fields are populated vs empty
    all_keys = set()
    populated_counts = {}
    for feat in data_bldg["features"]:
        props = feat.get("properties", {})
        for k, v in props.items():
            all_keys.add(k)
            if v and str(v).strip():
                populated_counts[k] = populated_counts.get(k, 0) + 1

    print(f"\n  Property population analysis ({len(data_bldg['features'])} buildings):")
    for key in sorted(all_keys):
        count = populated_counts.get(key, 0)
        pct = (count / len(data_bldg["features"])) * 100 if data_bldg["features"] else 0
        print(f"    {key:20s}: {count:3d}/{len(data_bldg['features'])} ({pct:.0f}%)")

    # Show interesting populated fields for first 5 buildings
    interesting_fields = [
        "BuildID", "BuildName", "BuildNameEn", "Campus", "CampusID",
        "Floors", "UnFloors", "FArea", "Unit", "address", "BuildCategory",
        "BuildType", "BuildTypeName", "view360", "DescCh", "DescEn",
        "PropertyID", "PropertyName", "Lifetime", "Date_Accept",
        "Perimeter", "add_area", "Monument"
    ]
    print("\n  Detailed building info (all 47):")
    for feat in data_bldg["features"]:
        props = feat.get("properties", {})
        bid = props.get("BuildID", "?")
        bname = props.get("BuildName", "?")
        bname_en = props.get("BuildNameEn", "?")
        campus = props.get("Campus", "?")
        floors = props.get("Floors", "?")
        unfloors = props.get("UnFloors", "?")
        unit = props.get("Unit", "?")
        addr = props.get("address", "?")
        bcat = props.get("BuildCategory", "?")
        btype = props.get("BuildTypeName", "?")
        view = props.get("view360", "?")
        desc = str(props.get("DescCh", ""))[:80]
        print(f"    [{bid}] {bname} / {bname_en}")
        print(f"        Campus={campus}, Floors={floors}/{unfloors}, Unit={unit}")
        print(f"        Category={bcat}, Type={btype}, Addr={addr}")
        if view and str(view).strip():
            print(f"        360View={view}")
        if desc.strip():
            print(f"        Desc={desc}")

# ============================================================
# Part 3: Deep inspection of gis_campus (rich metadata)
# ============================================================
print("\n--- Part 3: Deep inspection of gis:gis_campus ---")
if data_campus and "features" in data_campus:
    for feat in data_campus["features"]:
        props = feat.get("properties", {})
        print(f"  Campus: {props.get('NAME_CH')} / {props.get('NAME_EN')}")
        for k, v in sorted(props.items()):
            if k != "the_geom":
                print(f"    {k}: {v}")

# ============================================================
# Part 4: Try BBOX with correct coordinates (EPSG:4326)
# ============================================================
print("\n--- Part 4: BBOX queries with correct coordinates ---")

# Based on campus data, derive correct BBOX
# Let's read the actual coordinates from the campus feature first
if data_campus and "features" in data_campus:
    for feat in data_campus["features"]:
        name = feat["properties"].get("NAME_CH", "?")
        geom = feat["geometry"]
        coords_flat = []
        def flatten_coords2(c):
            if isinstance(c[0], (int, float)):
                coords_flat.append(c)
            else:
                for sub in c:
                    flatten_coords2(sub)
        flatten_coords2(geom["coordinates"])
        if coords_flat:
            xs = [c[0] for c in coords_flat]
            ys = [c[1] for c in coords_flat]
            bbox = f"{min(xs)},{min(ys)},{max(xs)},{max(ys)}"
            print(f"\n  Campus '{name}' BBOX: {bbox}")

            # Now try BBOX filter on buildings
            for layer in ["gis:gis_building_geom", "gis:gis_restaurant", "gis:gis_parking", "gis:gis_aed"]:
                data_bbox = get_json(layer, {"CQL_FILTER": f"BBOX(the_geom,{bbox})"})
                if data_bbox and "features" in data_bbox:
                    n = len(data_bbox["features"])
                    if n > 0:
                        print(f"    {layer}: {n} features")
                        names = [f["properties"].get("name_ch") or f["properties"].get("BuildName") or "?" for f in data_bbox["features"][:5]]
                        print(f"      Sample: {names}")
                time.sleep(0.2)

# ============================================================
# Part 5: Try different output formats
# ============================================================
print("\n--- Part 5: Alternative output formats ---")

formats_to_try = [
    "application/json",
    "text/xml; subtype=gml/3.1.1",
    "csv",
    "application/vnd.google-earth.kml+xml",
    "SHAPE-ZIP",
]

for fmt in formats_to_try:
    r = wfs_get({
        "request": "GetFeature",
        "typeName": "gis:gis_building",
        "maxFeatures": "2",
        "outputFormat": fmt,
    })
    if r:
        ct = r.headers.get("content-type", "?")
        print(f"  Format '{fmt}': status={r.status_code}, content-type={ct}, size={len(r.content)} bytes")
    time.sleep(0.3)

# ============================================================
# Part 6: Try GetPropertyValue (WFS 2.0 operation)
# ============================================================
print("\n--- Part 6: GetPropertyValue attempts ---")
for prop in ["BuildName", "BuildNameEn", "Campus", "Floors"]:
    r = wfs_get({
        "request": "GetPropertyValue",
        "typeNames": "gis:gis_building",
        "valueReference": prop,
        "version": "2.0.0",
    })
    if r:
        if r.status_code == 200:
            # Try to extract values
            import re
            values = re.findall(r"<[^>]*>([^<]+)</", r.text)
            unique_vals = list(set(values))[:20]
            print(f"  {prop}: {len(values)} values, unique={unique_vals}")
        else:
            print(f"  {prop}: HTTP {r.status_code}")
    time.sleep(0.3)

# ============================================================
# Part 7: Try to find other workspaces besides 'gis'
# ============================================================
print("\n--- Part 7: Check for other workspaces ---")
r = wfs_get({"request": "GetCapabilities"})
if r and r.status_code == 200:
    import re
    # Look for any namespace declarations
    ns_matches = re.findall(r'xmlns:(\w+)="([^"]+)"', r.text)
    print(f"  Namespace declarations found: {len(ns_matches)}")
    for ns, uri in ns_matches:
        if ns not in ("wfs", "xsi", "xlink", "gml", "ogc", "ows", "xs"):
            print(f"    {ns}: {uri}")

    # Look for all layer names (any namespace)
    all_layers = re.findall(r"<Name>([^<]+)</Name>", r.text)
    non_gis = [l for l in all_layers if not l.startswith("gis:")]
    if non_gis:
        print(f"  Non-gis layers: {non_gis}")
    else:
        print(f"  All {len(all_layers)} layers are in 'gis' namespace")

# ============================================================
# Part 8: Check for stored queries (WFS 2.0)
# ============================================================
print("\n--- Part 8: Stored queries ---")
r = wfs_get({
    "request": "ListStoredQueries",
    "version": "2.0.0",
})
if r and r.status_code == 200:
    import re
    queries = re.findall(r'id="([^"]+)"', r.text)
    print(f"  Stored queries: {queries}")
else:
    print(f"  ListStoredQueries: {'HTTP ' + str(r.status_code) if r else 'failed'}")

# ============================================================
# Part 9: Try specific CQL filters for interesting data
# ============================================================
print("\n--- Part 9: Targeted CQL filters ---")

# Buildings with 360 views
data_360 = get_json("gis:gis_building", {"CQL_FILTER": "view360 IS NOT NULL"})
if data_360 and "features" in data_360:
    buildings_360 = [(f["properties"].get("BuildName"), f["properties"].get("view360"))
                     for f in data_360["features"]
                     if f["properties"].get("view360") and str(f["properties"].get("view360")).strip()]
    print(f"  Buildings with 360 views: {len(buildings_360)}")
    for name, url in buildings_360:
        print(f"    {name}: {url}")

# Buildings with descriptions
data_desc = get_json("gis:gis_building", {"CQL_FILTER": "DescCh IS NOT NULL"})
if data_desc and "features" in data_desc:
    buildings_desc = [(f["properties"].get("BuildName"), f["properties"].get("DescCh"), f["properties"].get("DescEn"))
                      for f in data_desc["features"]
                      if f["properties"].get("DescCh") and str(f["properties"].get("DescCh")).strip()]
    print(f"\n  Buildings with Chinese descriptions: {len(buildings_desc)}")
    for name, desc_ch, desc_en in buildings_desc[:10]:
        print(f"    {name}:")
        print(f"      CH: {str(desc_ch)[:100]}")
        print(f"      EN: {str(desc_en)[:100]}" if desc_en else "      EN: (none)")

# Buildings by campus
for campus_val in ["1", "2", "3", "YM", "GF", "陽明", "光復"]:
    data_c = get_json("gis:gis_building", {
        "CQL_FILTER": f"Campus = '{campus_val}'",
        "maxFeatures": "2",
    })
    if data_c and "features" in data_c and len(data_c["features"]) > 0:
        print(f"\n  Buildings with Campus='{campus_val}': {len(data_c['features'])} features")
        for f in data_c["features"][:2]:
            print(f"    {f['properties'].get('BuildName')}")

# Buildings by CampusID
for cid in ["1", "2", "3"]:
    data_cid = get_json("gis:gis_building", {
        "CQL_FILTER": f"CampusID = '{cid}'",
        "maxFeatures": "2",
    })
    if data_cid and "features" in data_cid and len(data_cid["features"]) > 0:
        print(f"\n  Buildings with CampusID='{cid}': {len(data_cid['features'])} features")
        for f in data_cid["features"][:2]:
            print(f"    {f['properties'].get('BuildName')} / {f['properties'].get('BuildNameEn')}")

# Buildings by BuildCategory
data_cats = get_json("gis:gis_building")
if data_cats and "features" in data_cats:
    categories = set()
    types = set()
    for f in data_cats["features"]:
        cat = f["properties"].get("BuildCategory")
        bt = f["properties"].get("BuildType")
        btn = f["properties"].get("BuildTypeName")
        if cat:
            categories.add(cat)
        if bt:
            types.add((bt, btn))
    print(f"\n  BuildCategory values: {sorted(categories)}")
    print(f"  BuildType/Name pairs: {sorted(types)}")

# ============================================================
# Part 10: Explore busstop details with route info
# ============================================================
print("\n--- Part 10: Bus stop details ---")
data_bus = get_json("gis:gis_busstop")
if data_bus and "features" in data_bus:
    for feat in data_bus["features"]:
        props = feat["properties"]
        coords = feat["geometry"]["coordinates"] if feat.get("geometry") else "?"
        print(f"  {props.get('name_ch')} / {props.get('name_en')}")
        print(f"    Routes: {props.get('desc_ch')}")
        print(f"    Coords: {coords}")

# ============================================================
# Part 11: Explore sport facilities
# ============================================================
print("\n--- Part 11: Sport facilities ---")
data_sport = get_json("gis:gis_sport")
if data_sport and "features" in data_sport:
    for feat in data_sport["features"]:
        props = feat["properties"]
        print(f"  {props.get('name_ch')} / {props.get('name_en')}")
        if props.get("url"):
            print(f"    URL: {props['url']}")
        if props.get("photo"):
            print(f"    Photo: {props['photo']}")

# ============================================================
# Part 12: Explore campus photos with URLs
# ============================================================
print("\n--- Part 12: Campus photos ---")
data_photos = get_json("gis:gis_campusphotos")
if data_photos and "features" in data_photos:
    for feat in data_photos["features"]:
        props = feat["properties"]
        print(f"  {props.get('name_ch')} / {props.get('name_en')}")
        if props.get("url"):
            print(f"    URL: {props['url']}")
        if props.get("keyword"):
            print(f"    Keywords: {props['keyword']}")

# Save combined deep analysis
print("\n--- Saving combined results ---")
combined = {
    "timestamp": datetime.now().isoformat(),
    "building_full": data_bldg if data_bldg and "features" in data_bldg else None,
    "campus_full": data_campus if data_campus and "features" in data_campus else None,
    "busstop_full": data_bus if (data_bus and "features" in data_bus) else None,
}
save_json(combined, "DEEP_PROPERTY_ANALYSIS.json")

print(f"\nCompleted: {datetime.now().isoformat()}")
