-- Incidents as first observed. Rows here are never updated: when a feed serves a
-- changed version of a record it goes to incident_amendments instead, so the
-- original survives a reclassification, a reopened case or a withdrawn record.
-- occurred_at is local time (America/Chicago); the services return UTC epochs
-- and ingest.py converts on the way in.
CREATE TABLE IF NOT EXISTS incidents (
    source       TEXT NOT NULL,  -- opd | sarpy | cbpd | opd_csv
    source_key   TEXT NOT NULL,  -- PK (opd) | IncidentId (sarpy) | cfs_number (cbpd)
    agency       TEXT NOT NULL,
    case_id      TEXT,
    occurred_at  TEXT NOT NULL,  -- ISO 8601, no offset
    category     TEXT,           -- each feed's own taxonomy, not comparable
    call_type    TEXT,           -- CadTypeDesc (sarpy) | incident_code (cbpd)
    disposition  TEXT,           -- CAD disposition, sarpy and cbpd
    offense_desc TEXT,           -- StatuteDesc (sarpy) | statute text (opd_csv)
    is_stop      INTEGER NOT NULL DEFAULT 0,  -- officer-initiated vehicle stop
    address      TEXT,
    lat          REAL,
    lon          REAL,
    digest       TEXT NOT NULL,  -- hash of the payload, for change detection
    first_seen   TEXT,           -- when ingest first saw it; NULL if pre-dating
    PRIMARY KEY (source, source_key)
);

CREATE INDEX IF NOT EXISTS incidents_occurred ON incidents (occurred_at);
CREATE INDEX IF NOT EXISTS incidents_agency   ON incidents (agency, occurred_at);
CREATE INDEX IF NOT EXISTS incidents_category ON incidents (category);
CREATE INDEX IF NOT EXISTS incidents_stop     ON incidents (is_stop, occurred_at);

-- Every distinct later version of a record, one row per version. Keyed on the
-- payload digest, so a version is stored once no matter how many runs serve it.
-- A record that reverts to a payload already on file is therefore not recorded
-- again: this holds the set of distinct states observed, not a strict timeline.
CREATE TABLE IF NOT EXISTS incident_amendments (
    source       TEXT NOT NULL,
    source_key   TEXT NOT NULL,
    agency       TEXT NOT NULL,
    case_id      TEXT,
    occurred_at  TEXT NOT NULL,
    category     TEXT,
    call_type    TEXT,
    disposition  TEXT,
    offense_desc TEXT,
    is_stop      INTEGER NOT NULL DEFAULT 0,
    address      TEXT,
    lat          REAL,
    lon          REAL,
    digest       TEXT NOT NULL,
    seen_at      TEXT NOT NULL,  -- when this version was first observed
    PRIMARY KEY (source, source_key, digest)
);

CREATE INDEX IF NOT EXISTS amendments_key  ON incident_amendments (source, source_key);
CREATE INDEX IF NOT EXISTS amendments_seen ON incident_amendments (seen_at);

-- The newest known version of each record: its latest amendment, or the
-- original where a record has never been amended.
CREATE VIEW IF NOT EXISTS incidents_current AS
SELECT source, source_key, agency, case_id, occurred_at, category, call_type,
       disposition, offense_desc, is_stop, address, lat, lon, observed_at,
       amended
FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY source, source_key
                                 ORDER BY amended DESC, observed_at DESC) AS rn
    FROM (
        SELECT source, source_key, agency, case_id, occurred_at, category,
               call_type, disposition, offense_desc, is_stop, address, lat, lon,
               first_seen AS observed_at, 0 AS amended
        FROM incidents
        UNION ALL
        SELECT source, source_key, agency, case_id, occurred_at, category,
               call_type, disposition, offense_desc, is_stop, address, lat, lon,
               seen_at AS observed_at, 1 AS amended
        FROM incident_amendments
    )
)
WHERE rn = 1;

-- What the feed actually served, one row per version, keyed the same way
-- incident_amendments is. A parse that turns out wrong or a field a feed adds
-- later can only be applied to history if the bytes were kept, and the feeds
-- age out, so there is no second chance to fetch them.
CREATE TABLE IF NOT EXISTS raw_records (
    source     TEXT NOT NULL,
    source_key TEXT NOT NULL,
    digest     TEXT NOT NULL,  -- the version of the record this payload produced
    fetched_at TEXT NOT NULL,
    payload    TEXT NOT NULL,  -- the feature object as served, JSON
    PRIMARY KEY (source, source_key, digest)
);

-- Searches run against an agency's ALPR network, from its Flock transparency
-- portal. The portal serves a rolling 30 days and the export is already the
-- whole record: no field here is derived, so there is no separate raw copy.
-- userId is redacted to *** by Flock, so searches cannot be attributed to an
-- officer, and most carry no reason despite the portals' stated access policy.
CREATE TABLE IF NOT EXISTS alpr_searches (
    agency        TEXT NOT NULL,  -- portal slug the export came from
    search_id     TEXT NOT NULL,  -- Flock's own UUID, stable across exports
    searched_at   TEXT NOT NULL,  -- ISO 8601 UTC, as published
    network_count INTEGER,        -- camera networks the search reached across
    reason        TEXT,           -- free text, blank on most searches
    user_id       TEXT,           -- redacted upstream
    imported_at   TEXT NOT NULL,
    PRIMARY KEY (agency, search_id)
);

CREATE INDEX IF NOT EXISTS searches_when ON alpr_searches (searched_at);

-- ALPR cameras from OpenStreetMap (ODbL). first_seen/last_seen track when a node
-- entered and was last present in the Overpass result, so cameras that appear or
-- are removed are visible over time.
CREATE TABLE IF NOT EXISTS alpr_cameras (
    osm_id       INTEGER PRIMARY KEY,
    lat          REAL NOT NULL,
    lon          REAL NOT NULL,
    manufacturer TEXT,
    operator     TEXT,
    direction    TEXT,
    first_seen   TEXT NOT NULL,
    last_seen    TEXT NOT NULL,
    tags         TEXT NOT NULL  -- full OSM tag dict as JSON
);
