"""Unit tests for the fddb.info source adapter."""

from dataclasses import dataclass
from unittest.mock import patch, MagicMock, call

import pytest

from byteb4rb1e.homeostat.envelope import Envelope
from byteb4rb1e.homeostat.adapters.fddb import (
    FddbAdapter,
    LoginFailed,
)
from byteb4rb1e.homeostat.util.http import HttpResponse


# -- Helpers -----------------------------------------------------------------


def fake_response(body, status_code=200):
    return HttpResponse(
        status_code=status_code,
        headers={},
        body=body.encode() if isinstance(body, str) else body,
    )


@pytest.fixture
def adapter():
    return FddbAdapter(
        username="testuser", password="testpass"
    )


# -- Login -------------------------------------------------------------------


class TestLogin:
    def test_successful_login(self, adapter):
        resp = fake_response("<html>... logout ...</html>")
        with patch.object(
            adapter._session, "post", return_value=resp
        ):
            adapter.login()
        assert adapter._logged_in is True

    def test_login_detects_german_indicator(self, adapter):
        resp = fake_response("<html>... Abmelden ...</html>")
        with patch.object(
            adapter._session, "post", return_value=resp
        ):
            adapter.login()
        assert adapter._logged_in is True

    def test_failed_login_raises(self, adapter):
        resp = fake_response("<html>Login failed</html>")
        with patch.object(
            adapter._session, "post", return_value=resp
        ):
            with pytest.raises(LoginFailed):
                adapter.login()

    def test_login_sends_credentials(self, adapter):
        resp = fake_response("<html>logout</html>")
        with patch.object(
            adapter._session, "post", return_value=resp
        ) as mock_post:
            adapter.login()

        _, kwargs = mock_post.call_args
        assert kwargs["data"]["loginemailorusername"] == "testuser"
        assert kwargs["data"]["loginpassword"] == "testpass"


# -- Require login -----------------------------------------------------------


class TestRequireLogin:
    def test_month_diary_requires_login(self, adapter):
        with pytest.raises(RuntimeError, match="Not logged in"):
            adapter.month_diary(3, 2026)

    def test_day_detail_requires_login(self, adapter):
        with pytest.raises(RuntimeError, match="Not logged in"):
            adapter.day_detail("/some/url")


# -- Month diary -------------------------------------------------------------


class TestMonthDiary:
    def test_returns_envelope_with_html(self, adapter):
        adapter._logged_in = True
        html = "<html><body>diary page</body></html>"
        resp = fake_response(html)

        with patch.object(
            adapter._session, "get", return_value=resp
        ):
            env = adapter.month_diary(3, 2026)

        assert isinstance(env, Envelope)
        assert env.source == "fddb"
        assert env.endpoint == "notepad/month/2026-03"
        assert env.payload == html
        assert env.fetched_at

    def test_passes_correct_params(self, adapter):
        adapter._logged_in = True
        resp = fake_response("<html></html>")

        with patch.object(
            adapter._session, "get", return_value=resp
        ) as mock_get:
            adapter.month_diary(1, 2025)

        _, kwargs = mock_get.call_args
        assert kwargs["params"]["month"] == "1"
        assert kwargs["params"]["year"] == "2025"
        assert kwargs["params"]["action"] == "npfe"
        assert kwargs["params"]["mode"] == "2"


# -- Day detail --------------------------------------------------------------


class TestDayDetail:
    def test_returns_envelope_with_html(self, adapter):
        adapter._logged_in = True
        html = "<html><body>detail page</body></html>"
        resp = fake_response(html)

        with patch.object(
            adapter._session, "get", return_value=resp
        ):
            env = adapter.day_detail(
                "https://fddb.info/db/i18n/myday20260319"
            )

        assert isinstance(env, Envelope)
        assert env.source == "fddb"
        assert env.payload == html

    def test_relative_url_gets_base_prepended(self, adapter):
        adapter._logged_in = True
        resp = fake_response("<html></html>")

        with patch.object(
            adapter._session, "get", return_value=resp
        ) as mock_get:
            adapter.day_detail("/db/i18n/myday20260319")

        url = mock_get.call_args[0][0]
        assert url.startswith("https://fddb.info/")

    def test_absolute_url_used_as_is(self, adapter):
        adapter._logged_in = True
        resp = fake_response("<html></html>")

        with patch.object(
            adapter._session, "get", return_value=resp
        ) as mock_get:
            adapter.day_detail(
                "https://fddb.info/db/i18n/myday20260319"
            )

        url = mock_get.call_args[0][0]
        assert url == (
            "https://fddb.info/db/i18n/myday20260319"
        )


# -- Envelope ----------------------------------------------------------------


class TestEnvelope:
    def test_envelope_is_frozen(self):
        env = Envelope(
            source="fddb",
            endpoint="/test",
            fetched_at="2026-03-20T00:00:00+00:00",
            payload="<html></html>",
        )
        with pytest.raises(AttributeError):
            env.source = "other"
