"""MIK North Sea operator app. Data and authority arrive only through the Horizon app host."""

import marimo

__generated_with = "0.23.14"
app = marimo.App(width="full")


@app.cell
def _():
    import marimo as mo
    from scrydon import apps

    return apps, mo


@app.cell
def _(apps):
    access = apps.declare(
        ontologies=[apps.ontology("scrydon-pack-mik-north-sea-v2", alias="mik")],
        queries=[
            apps.query(
                "tracks", ontology="mik", object_type="MaritimeTrack",
                properties=[
                    "trackId", "vesselId", "observationId", "sourceId", "sourceEntityId",
                    "observedAt", "receivedAt", "latitude", "longitude", "heading",
                    "speed", "quality", "freshness",
                ],
                max_objects=1000, live=True, stale_after_ms=120_000,
                max_interpolation_gap_ms=15_000,
            ),
            apps.query(
                "zones", ontology="mik", object_type="MaritimeZone",
                properties=["areaId", "name", "category", "boundary"],
                filter=[{"property": "category", "op": "eq", "value": "restricted"}],
                max_objects=100, live=True, stale_after_ms=86_400_000,
            ),
            apps.query(
                "interest_zones", ontology="mik", object_type="MaritimeZone",
                properties=["areaId", "name", "category", "boundary"],
                filter=[{"property": "category", "op": "eq", "value": "interest"}],
                max_objects=100, live=True, required=False, stale_after_ms=86_400_000,
            ),
            apps.query(
                "vessels", ontology="mik", object_type="MaritimeVessel",
                properties=[
                    "vesselId", "name", "mmsi", "imo", "flag", "vesselType",
                    "riskScore", "riskLevel", "riskReasons", "lastLatitude",
                    "lastLongitude", "heading", "lastSeenAt", "provenance",
                ],
                max_objects=1000, live=True, required=False,
                stale_after_ms=86_400_000,
            ),
            apps.query(
                "replay", ontology="mik", object_type="MaritimeReplayEvent",
                properties=[
                    "eventId", "rule", "severity", "areaId", "vesselId", "firedAt",
                    "summary", "provenance",
                ],
                max_objects=100, live=True, required=False, stale_after_ms=86_400_000,
            ),
            apps.query(
                "exposure", ontology="mik", object_type="MaritimeZoneExposure",
                properties=[
                    "exposureId", "vesselId", "vesselName", "areaId", "zoneName",
                    "zoneCategory", "riskLevel", "computedAt", "provenance",
                ],
                max_objects=1000, live=True, required=False, stale_after_ms=86_400_000,
            ),
            apps.query(
                "detections", ontology="mik", object_type="MaritimeDetection",
                properties=[
                    "detectionId", "watchSlug", "kind", "severity", "areaId", "entityId",
                    "firedAt", "acknowledgementStatus", "acknowledgedBy", "acknowledgedAt",
                ],
                max_objects=1000, live=True, required=False, stale_after_ms=120_000,
            ),
        ],
        links=[apps.link(
            "track-vessel", ontology="mik", link_type="MaritimeTrackVessel",
            source_query="tracks", target_query="vessels", max_objects=1,
            required=False,
        )],
        actions=[apps.allow_action(
            "acknowledge-mik-detection", ontology="mik",
            action_type="acknowledge-mik-detection",
            input_properties=["detectionId"], required=False,
        )],
        watches=[
            apps.allow_watch("mik-restricted-area", ontology="mik", watch="mik-restricted-area", required=False),
            apps.allow_watch("mik-missing-vessel-report", ontology="mik", watch="mik-missing-vessel-report", required=False),
        ],
    )
    return access


@app.cell
def _(apps):
    restricted = apps.zones(
        "zones", geometry="boundary", label="name", classification="category",
        title="Restricted area",
    )
    interest = apps.zones(
        "interest_zones", geometry="boundary", label="name", classification="category",
        title="Zones of interest (approx.)",
    )
    # Registry vessels have no live track: each draws as a ship at its last
    # reported position, turned to its last course and coloured by risk.
    # Selecting one selects it in the "Vessels of interest" list too.
    last_seen = apps.points(
        "vessels", latitude="lastLatitude", longitude="lastLongitude", label="name",
        classification="riskLevel", heading="heading", selection_group="vessels",
        title="Vessels of interest (last position)",
    )
    picture = apps.map(
        "tracks", latitude="latitude", longitude="longitude",
        observed_at="observedAt", received_at="receivedAt",
        label="vesselId", heading="heading",
        zone_layers=[restricted, interest], point_layers=[last_seen],
        center=(2.8, 51.6), zoom=7, selection_group="contacts",
        title="North Sea picture",
    )
    return (picture,)


@app.cell
def _(apps):
    contacts = apps.table(
        "tracks", columns={
            # The first column is the row's select button: the stable trackId,
            # which an uncorrelated radar contact has and a vesselId it lacks.
            "trackId": "MaritimeTrack", "vesselId": "MaritimeVessel",
            "freshness": "Freshness",
        },
        selection_group="contacts", title="Live contacts",
    )
    details = apps.details(
        "tracks", fields={
            "trackId": "Track ID", "vesselId": "Vessel ID",
            "sourceId": "Accepted source",
            "sourceEntityId": "Source contact", "observedAt": "Observed",
            "receivedAt": "Received", "speed": "Speed", "quality": "Quality",
        }, selection_group="contacts", title="Selected track",
    )
    registry = apps.related(
        "track-vessel", columns={
            "name": "Registered name", "mmsi": "MMSI", "flag": "Flag", "riskLevel": "Risk",
        },
        source_selection_group="contacts", selection_group="registry",
        title="Linked vessel registry",
    )
    return contacts, details, registry


@app.cell
def _(apps):
    watchlist = apps.table(
        "vessels", columns={
            "name": "Vessel", "vesselType": "Type", "flag": "Flag",
            "riskLevel": "Risk", "riskScore": "Score",
        },
        selection_group="vessels", title="Vessels of interest (fictional)",
    )
    vessel_details = apps.details(
        "vessels", fields={
            "riskReasons": "Why", "riskScore": "Risk score", "imo": "IMO",
            "mmsi": "MMSI", "lastSeenAt": "Last seen", "provenance": "Provenance",
        }, selection_group="vessels", title="Selected vessel",
    )
    # Derived by the exposure.py notebook: registry SQL joined with MaritimeZone.
    exposure = apps.table(
        "exposure", columns={
            "vesselName": "Vessel", "zoneName": "Area", "riskLevel": "Risk",
            "computedAt": "Computed",
        },
        selection_group="exposure", title="Vessels inside a governed area",
    )
    return exposure, vessel_details, watchlist


@app.cell
def _(apps):
    detections = apps.alerts(
        "detections", columns={
            "watchSlug": "Rule", "severity": "Severity", "firedAt": "Detected",
            "acknowledgementStatus": "Acknowledgement",
        },
        severity="severity", status="acknowledgementStatus",
        acknowledge_action="acknowledge-mik-detection", acknowledge_input="detectionId",
        selection_group="alerts",
        title="Independent watch detections",
    )
    detection_details = apps.details(
        "detections", fields={
            "watchSlug": "Rule", "kind": "Event class", "areaId": "Area",
            "entityId": "MaritimeTrack",
            "firedAt": "Detected", "acknowledgedBy": "Acknowledged by",
            "acknowledgedAt": "Acknowledged at",
        }, selection_group="alerts", title="Selected detection",
    )
    replayed = apps.table(
        "replay", columns={
            "summary": "Event", "severity": "Severity", "firedAt": "Detected",
        },
        selection_group="replay", title="Replayed events (demo)",
    )
    replay_details = apps.details(
        "replay", fields={
            "rule": "Rule", "areaId": "Area", "vesselId": "Vessel",
            "provenance": "Provenance",
        }, selection_group="replay", title="Selected replay",
    )
    return detection_details, detections, replay_details, replayed


@app.cell
def _(
    contacts, detection_details, detections, details, exposure, mo, picture,
    registry, replay_details, replayed, vessel_details, watchlist,
):
    # The picture takes the viewer's full height (the map sizes itself to the
    # frame); the rail beside it is a tab per worklist, each with the inspector
    # its selection drives.
    mo.hstack(
        [
            picture,
            mo.ui.tabs({
                "Contacts": mo.vstack([contacts, details, registry], gap=0.75),
                "Vessels of interest": mo.vstack(
                    [watchlist, vessel_details, exposure], gap=0.75,
                ),
                "Detections": mo.vstack(
                    [detections, detection_details, replayed, replay_details], gap=0.75,
                ),
            }),
        ],
        widths=[2, 1], gap=1, align="start",
    )
    return


if __name__ == "__main__":
    app.run()
