"""Unit tests for federation DTO conversion functions."""
from __future__ import annotations

from datetime import datetime
from types import SimpleNamespace
from unittest.mock import patch

import pytest

from shared.services.federation_impl import (
    _actor_to_dto, _activity_to_dto, _follower_to_dto,
    _remote_actor_to_dto, _remote_post_to_dto,
)


def _actor(**kwargs):
    defaults = {
        "id": 1, "user_id": 10,
        "preferred_username": "alice",
        "public_key_pem": "-----BEGIN PUBLIC KEY-----",
        "display_name": "Alice", "summary": "Hello",
        "created_at": datetime(2025, 1, 1),
    }
    defaults.update(kwargs)
    return SimpleNamespace(**defaults)


def _activity(**kwargs):
    defaults = {
        "id": 1, "activity_id": "https://example.com/activity/1",
        "activity_type": "Create", "actor_profile_id": 1,
        "object_type": "Note", "object_data": {"content": "hi"},
        "published": datetime(2025, 1, 1), "is_local": True,
        "source_type": "post", "source_id": 42, "ipfs_cid": None,
    }
    defaults.update(kwargs)
    return SimpleNamespace(**defaults)


def _follower(**kwargs):
    defaults = {
        "id": 1, "actor_profile_id": 1,
        "follower_acct": "bob@remote.com",
        "follower_inbox": "https://remote.com/inbox",
        "follower_actor_url": "https://remote.com/users/bob",
        "created_at": datetime(2025, 1, 1),
        "app_domain": "federation.rose-ash.com",
    }
    defaults.update(kwargs)
    return SimpleNamespace(**defaults)


def _remote_actor(**kwargs):
    defaults = {
        "id": 1, "actor_url": "https://remote.com/users/bob",
        "inbox_url": "https://remote.com/inbox",
        "preferred_username": "bob", "domain": "remote.com",
        "display_name": "Bob", "summary": "Hi",
        "icon_url": "https://remote.com/avatar.jpg",
        "shared_inbox_url": None, "public_key_pem": None,
    }
    defaults.update(kwargs)
    return SimpleNamespace(**defaults)


def _remote_post(**kwargs):
    defaults = {
        "id": 1, "remote_actor_id": 1,
        "object_id": "https://remote.com/note/1",
        "content": "<p>Hello</p>", "summary": None,
        "url": "https://remote.com/note/1",
        "attachment_data": [{"type": "Image", "url": "img.jpg"}],
        "tag_data": [{"type": "Hashtag", "name": "#test"}],
        "published": datetime(2025, 1, 1),
    }
    defaults.update(kwargs)
    return SimpleNamespace(**defaults)


class TestActorToDto:
    @patch("shared.services.federation_impl._domain", return_value="fed.example.com")
    def test_basic(self, mock_domain):
        dto = _actor_to_dto(_actor())
        assert dto.preferred_username == "alice"
        assert dto.inbox_url == "https://fed.example.com/users/alice/inbox"
        assert dto.outbox_url == "https://fed.example.com/users/alice/outbox"
        assert dto.user_id == 10
        assert dto.display_name == "Alice"


class TestActivityToDto:
    def test_fields(self):
        dto = _activity_to_dto(_activity())
        assert dto.activity_type == "Create"
        assert dto.object_type == "Note"
        assert dto.is_local is True
        assert dto.ipfs_cid is None


class TestFollowerToDto:
    def test_fields(self):
        dto = _follower_to_dto(_follower())
        assert dto.follower_acct == "bob@remote.com"
        assert dto.app_domain == "federation.rose-ash.com"


class TestRemoteActorToDto:
    def test_fields(self):
        dto = _remote_actor_to_dto(_remote_actor())
        assert dto.preferred_username == "bob"
        assert dto.domain == "remote.com"
        assert dto.icon_url == "https://remote.com/avatar.jpg"


class TestRemotePostToDto:
    def test_with_actor(self):
        actor = _remote_actor()
        dto = _remote_post_to_dto(_remote_post(), actor=actor)
        assert dto.content == "<p>Hello</p>"
        assert dto.actor is not None
        assert dto.actor.preferred_username == "bob"

    def test_without_actor(self):
        dto = _remote_post_to_dto(_remote_post(), actor=None)
        assert dto.actor is None

    def test_none_content_becomes_empty(self):
        dto = _remote_post_to_dto(_remote_post(content=None))
        assert dto.content == ""

    def test_none_attachments_becomes_list(self):
        dto = _remote_post_to_dto(_remote_post(attachment_data=None))
        assert dto.attachments == []

    def test_none_tags_becomes_list(self):
        dto = _remote_post_to_dto(_remote_post(tag_data=None))
        assert dto.tags == []
