""".. title:: US Drought Monitor GeoJSON

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

Documentation for /geojson/usdm.py
----------------------------------

This service returns a GeoJSON representation of the US Drought Monitor
for a given date.  The date is specified in the `date` parameter, which
should be in the format of `YYYY-MM-DD`.  If no date is provided, the
latest valid USDM is returned.

Changelog
---------

- 2026-02-14: Renamed top level metadata `generation_time` to `generated_at`
  for better consistency across IEM services.
- 2024-08-09: Initial documentation release

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

Fetch the latest USDM:

https://mesonet.agron.iastate.edu/geojson/usdm.py

Fetch the USDM for closest date to 20 March 2024:

https://mesonet.agron.iastate.edu/geojson/usdm.py?date=2024-03-20

"""

import json
from datetime import date as dateobj
from datetime import timedelta
from typing import Annotated

from pydantic import Field
from pyiem.database import get_sqlalchemy_conn, sql_helper
from pyiem.exceptions import IncompleteWebRequest
from pyiem.webutil import CGIModel, iemapp

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


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

    callback: CALLBACK_FIELD = None
    date: Annotated[
        dateobj | None,
        Field(
            ge=dateobj(2000, 1, 1),
            description="Date to query for, YYYY-MM-DD",
        ),
    ] = None


def rectify_date(dt: dateobj):
    """Convert this tstamp into something we can actually use

    if '', use max valid from database
    if between tuesday and thursday at 8 AM, go back to last week
    back to tuesday
    """
    if dt is None:
        with get_sqlalchemy_conn("postgis") as conn:
            # Go get the latest USDM stored in the database!
            res = conn.execute(sql_helper("SELECT max(valid) from usdm"))
            res = res.fetchone()[0]
        return res

    offset = (dt.weekday() - 1) % 7
    return dt - timedelta(days=offset)


def run(ts: dateobj):
    """Actually do the hard work of getting the USDM in geojson"""
    data = json_response_dict(
        {
            "type": "FeatureCollection",
            "features": [],
        }
    )
    with get_sqlalchemy_conn("postgis") as conn:
        res = conn.execute(
            sql_helper(
                "SELECT ST_asGeoJson(geom) as geojson, dm, valid "
                "from usdm WHERE valid = :ts ORDER by dm ASC"
            ),
            {"ts": ts},
        )
        if res.rowcount == 0:
            # go back one week
            res = conn.execute(
                sql_helper(
                    "SELECT ST_asGeoJson(geom) as geojson, dm, valid "
                    "from usdm WHERE valid = :ts ORDER by dm ASC"
                ),
                {"ts": ts - timedelta(days=7)},
            )

        for row in res.mappings():
            data["features"].append(
                dict(
                    type="Feature",
                    id=row["dm"],
                    properties=dict(
                        date=row["valid"].strftime("%Y-%m-%d"), dm=row["dm"]
                    ),
                    geometry=json.loads(row["geojson"]),
                )
            )
    data["count"] = len(data["features"])
    return json.dumps(data)


def get_mckey(environ):
    """Get the key."""
    return f"/geojson/usdm.geojson|{environ['date']}"


@iemapp(
    help=__doc__,
    memcacheexpire=3600,
    memcachekey=get_mckey,
    schema=Schema,
    content_type="application/vnd.geo+json",
)
def application(environ, start_response):
    """Main Workflow"""
    headers = [("Content-type", "application/vnd.geo+json")]

    ts = rectify_date(environ["date"])
    if ts is None:
        raise IncompleteWebRequest("No USDM data found.")
    res = run(ts)
    start_response("200 OK", headers)
    return res
