""".. title:: Webcam Metadata GeoJSON

Return to `API Services </api/#json>`_ listing.

Documentation for /geojson/webcam.py
------------------------------------

This service emits a geojson with metadata for webcam information that is
active at the given timestamp/now.

Changelog
---------

- 2025-06-02: Added property `utc_valid` and `imgurl` to align with other
  services.
- 2024-06-30: Initial documentation release. Parameter `valid` added for
  consistency with other services.

Example Usage
-------------

Return current webcam information.

https://mesonet.agron.iastate.edu/geojson/webcam.geojson

"""

import json
from datetime import timezone
from typing import Annotated

from pydantic import AwareDatetime, Field
from pyiem.database import get_sqlalchemy_conn, sql_helper
from pyiem.reference import ISO8601
from pyiem.util import utc
from pyiem.webutil import CGIModel, iemapp

from iemweb.fields import CALLBACK_FIELD, NETWORK_FIELD
from iemweb.util import json_response_dict


class Schema(CGIModel):
    """See how we are called."""

    callback: CALLBACK_FIELD = None
    network: NETWORK_FIELD = "KCCI"
    ts: Annotated[
        AwareDatetime | None,
        Field(
            description="Optional *legacy* timestamp to request webcams for.",
        ),
    ] = None
    valid: Annotated[
        AwareDatetime | None,
        Field(
            description="Optional timestamp to request webcams for.",
        ),
    ] = None


def run(valid, network):
    """Actually do the hard work of getting the current SPS in geojson"""
    networks = [network]
    if network == "TV":
        networks = ["KCRG", "KCCI", "KELO", "ISUC", "MCFC"]
    params = {"networks": networks, "valid": valid}
    data = json_response_dict(
        {
            "type": "FeatureCollection",
            "features": [],
            "valid_at": (valid if valid is not None else utc()).strftime(
                ISO8601
            ),
        }
    )

    with get_sqlalchemy_conn("mesosite") as conn:
        if valid is None:
            res = conn.execute(
                sql_helper("""
                    SELECT *, ST_x(geom) as lon, ST_y(geom) as lat
                    from camera_current c, webcams w
                    WHERE valid > (now() - '15 minutes'::interval)
                    and c.cam = w.id and
                    w.network = ANY(:networks)
                    ORDER by name ASC
            """),
                params,
            )
        else:
            res = conn.execute(
                sql_helper("""
                    SELECT *, ST_x(geom) as lon, ST_y(geom) as lat
                    from camera_log c, webcams w
                    WHERE valid = :valid and c.cam = w.id
                    and w.network = ANY(:networks) ORDER by name ASC
            """),
                params,
            )
        for row in res.mappings():
            cv = row["valid"].astimezone(timezone.utc)
            url = (
                "https://mesonet.agron.iastate.edu/archive/data/"
                f"{cv:%Y/%m/%d}/camera/{row['cam']}/{row['cam']}_"
                f"{cv:%Y%m%d%H%M}.jpg"
            )
            data["features"].append(
                dict(
                    type="Feature",
                    id=row["id"],
                    properties={
                        "valid": cv.strftime(ISO8601),
                        "utc_valid": cv.strftime(ISO8601),
                        "cid": row["id"],
                        "name": row["name"],
                        "county": row["county"],
                        "state": row["state"],
                        "angle": row["drct"],
                        "url": url,
                        "imgurl": url,
                    },
                    geometry={
                        "type": "Point",
                        "coordinates": [row["lon"], row["lat"]],
                    },
                )
            )
    data["count"] = len(data["features"])
    return json.dumps(data)


def get_mckey(environ):
    """Return a memcache key."""
    stamp = environ["valid"]
    if stamp is None:
        stamp = environ["ts"]
    if stamp is None:
        return "/geojson/webcam.geojson"
    return f"/geojson/webcam.geojson|{stamp:%Y%m%d%H%M}"


@iemapp(
    help=__doc__,
    schema=Schema,
    memcachekey=get_mckey,
    memcacheexpire=15,
    content_type="application/vnd.geo+json",
)
def application(environ: dict, start_response: callable):
    """Do Main"""
    stamp = environ["valid"]
    if stamp is None:
        stamp = environ["ts"]
    res = run(stamp, environ["network"])
    start_response("200 OK", [("Content-type", "application/vnd.geo+json")])
    return res
