import datetime
import json

import pytest

pytest.importorskip("flask")

from pipelet_dashboard import (
    _build_hubject_evse_status_payload,
    _hubject_cfg,
    _resolve_hubject_push_endpoint,
    _summarize_connector_status,
    app,
)


def _extract_evse_record(payload: dict[str, object]) -> dict[str, object]:
    operator_entries = payload.get("OperatorEvseStatus")
    assert isinstance(operator_entries, list) and operator_entries
    operator_entry = operator_entries[0]
    assert isinstance(operator_entry, dict)

    records = operator_entry.get("EvseStatusRecords")
    assert isinstance(records, list) and records
    record = records[0]
    assert isinstance(record, dict)
    return record


def test_build_hubject_evse_status_payload_adds_last_update():
    metadata = {"operator_id": "DE*PIP", "evse_id": "DE*PIP*E123"}

    payload, operator_id = _build_hubject_evse_status_payload(
        metadata,
        chargepoint_id="DE*PIP*E123",
        status="Available",
        action="update",
    )

    assert operator_id == "DE*PIP"

    record = _extract_evse_record(payload)
    last_update = record.get("LastUpdate")
    assert isinstance(last_update, str)
    assert last_update.endswith("Z")

    parsed = datetime.datetime.fromisoformat(last_update.replace("Z", "+00:00"))
    assert parsed.tzinfo == datetime.timezone.utc

    now = datetime.datetime.now(datetime.timezone.utc)
    assert abs((now - parsed).total_seconds()) < 5


def test_build_hubject_evse_status_payload_preserves_override():
    override_timestamp = "2023-05-06T12:34:56Z"
    metadata = {
        "operator_id": "DE*PIP",
        "evse_id": "DE*PIP*E456",
        "additional_data": json.dumps(
            {"evse_record": {"LastUpdate": override_timestamp}}
        ),
    }

    payload, _ = _build_hubject_evse_status_payload(
        metadata,
        chargepoint_id="DE*PIP*E456",
        status="Available",
        action="update",
    )

    record = _extract_evse_record(payload)
    assert record["LastUpdate"] == override_timestamp


@pytest.mark.parametrize(
    "base_url, expected",
    [
        (
            "https://example.com",
            "https://example.com/api/oicp/evsepush/v23/operators/DE*PIP/data-records",
        ),
        (
            "https://example.com/api/oicp/",
            "https://example.com/api/oicp/evsepush/v23/operators/DE*PIP/data-records",
        ),
    ],
)
def test_resolve_hubject_push_endpoint_normalizes_base_url(
    monkeypatch: pytest.MonkeyPatch, base_url: str, expected: str
) -> None:
    monkeypatch.setattr("pipelet_dashboard.get_config_value", lambda key: None)
    monkeypatch.setitem(_hubject_cfg, "api_base_url", base_url)

    target = _resolve_hubject_push_endpoint("DE*PIP")

    assert target.url == expected


@pytest.mark.parametrize(
    "status, expected",
    [
        ("Occupied", "charging"),
        ("Disabled", "unavailable"),
        ("Inactive", "unavailable"),
    ],
)
def test_summarize_connector_status_handles_additional_valid_states(
    status: str, expected: str
) -> None:
    result = _summarize_connector_status([{"status": status}])

    assert result == expected


def test_summarize_connector_status_falls_back_to_unknown() -> None:
    result = _summarize_connector_status([{"status": "Maintenance"}])

    assert result == "unknown"


def test_api_update_redirect_returns_404_when_missing(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    class _DummyCursor:
        def __init__(self, connection):
            self._connection = connection
            self.rowcount = 0
            self._next_fetch = None

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc, tb):
            return False

        def execute(self, query, params=None):
            self._connection.queries.append(query)
            normalized = query.strip().upper()
            if normalized.startswith("SELECT 1 FROM OP_REDIRECTS"):
                self._next_fetch = None
                return

            pytest.fail(f"unexpected query executed: {query}")

        def fetchone(self):
            return self._next_fetch

    class _DummyConnection:
        def __init__(self):
            self.queries: list[str] = []
            self.closed = False
            self.committed = False

        def cursor(self):
            return _DummyCursor(self)

        def commit(self):
            self.committed = True

        def close(self):
            self.closed = True

    connection = _DummyConnection()

    monkeypatch.setattr("pipelet_dashboard.get_db_conn", lambda: connection)
    monkeypatch.setattr("pipelet_dashboard.ensure_op_redirects_columns", lambda conn: None)

    refresh_called = False

    def _fake_refresh() -> None:
        nonlocal refresh_called
        refresh_called = True

    monkeypatch.setattr("pipelet_dashboard.refresh_station_list_safely", _fake_refresh)
    monkeypatch.setattr("pipelet_dashboard.get_token", lambda: "secret-token")

    app.testing = True
    client = app.test_client()
    response = client.patch(
        "/api/op_redirects",
        json={
            "source_url": "/ocpp16/UNKNOWN",
            "ws_url": "ws://example.invalid/ocpp16/UNKNOWN",
        },
        headers={"Authorization": "Bearer secret-token"},
    )

    assert response.status_code == 404
    assert response.get_json() == {"error": "redirect not found"}
    assert not refresh_called
    assert connection.closed
    assert connection.queries == ["SELECT 1 FROM op_redirects WHERE source_url=%s"]
