"""
Tests for data models.
"""

from datetime import datetime

import pytest

from getbiji_box.models import (
    Attachment,
    AudioSectionInfo,
    ChildrenCountResult,
    Directory,
    FileMetaData,
    FollowItem,
    FollowListResult,
    Knowledge,
    KnowledgeListResult,
    LinkNoteDetail,
    LiveStreamPost,
    Note,
    NoteListResult,
    ProgressItem,
    QuotaInfo,
    Resource,
    ResourceListResult,
    Tag,
    TokenInfo,
    UploadTokenResult,
    User,
)


class TestTag:
    """Test cases for Tag model."""

    def test_from_dict(self):
        """Test creating Tag from dict."""
        data = {
            "id": "tag1",
            "name": "Python",
            "type": "text",
            "tag_type": "text",
        }
        tag = Tag.from_dict(data)
        assert tag.id == "tag1"
        assert tag.name == "Python"


class TestAttachment:
    """Test cases for Attachment model."""

    def test_from_dict_link(self):
        """Test creating link attachment."""
        data = {
            "type": "link",
            "url": "https://example.com",
            "title": "Example",
        }
        attachment = Attachment.from_dict(data)
        assert attachment.type == "link"
        assert attachment.url == "https://example.com"

    def test_from_dict_audio(self):
        """Test creating audio attachment."""
        data = {
            "type": "audio",
            "url": "https://example.com/audio.mp3",
            "duration": 120000,
        }
        attachment = Attachment.from_dict(data)
        assert attachment.type == "audio"
        assert attachment.duration == 120000


class TestNote:
    """Test cases for Note model."""

    def test_from_dict_simple(self):
        """Test creating simple Note from dict."""
        data = {
            "id": "note123",
            "title": "Test Note",
            "content": "Test content",
            "body_text": "Test body",
            "note_type": "plain_text",
            "entry_type": "manual",
            "source": "web",
            "tags": [],
            "attachments": [],
            "is_ai_generated": False,
            "created_at": "2024-01-01T00:00:00Z",
            "updated_at": "2024-01-01T00:00:00Z",
        }
        note = Note.from_dict(data)
        assert note.id == "note123"
        assert note.title == "Test Note"
        assert note.content == "Test content"

    def test_from_dict_with_tags(self):
        """Test creating Note with tags."""
        data = {
            "id": "note123",
            "title": "Test",
            "content": "Content",
            "tags": [
                {"id": "t1", "name": "Python", "type": "text", "tag_type": "text"},
                {"id": "t2", "name": "Learning", "type": "text", "tag_type": "text"},
            ],
        }
        note = Note.from_dict(data)
        assert len(note.tags) == 2
        assert note.tags[0].name == "Python"

    def test_from_dict_with_attachments(self):
        """Test creating Note with attachments."""
        data = {
            "id": "note123",
            "title": "Test",
            "content": "Content",
            "attachments": [
                {"type": "audio", "url": "https://example.com/audio.mp3", "duration": 120000},
            ],
        }
        note = Note.from_dict(data)
        assert len(note.attachments) == 1
        assert note.attachments[0].type == "audio"

    def test_from_dict_with_note_id_field(self):
        """Test creating Note when using note_id field instead of id."""
        data = {
            "note_id": "note456",
            "title": "Test",
            "content": "Content",
        }
        note = Note.from_dict(data)
        assert note.id == "note456"


class TestNoteListResult:
    """Test cases for NoteListResult model."""

    def test_from_dict(self):
        """Test creating NoteListResult from dict."""
        data = {
            "list": [
                {"id": "note1", "title": "Note 1", "content": "Content 1"},
                {"id": "note2", "title": "Note 2", "content": "Content 2"},
            ],
            "total_items": 2,
            "has_more": True,
            "limit": 10,
        }
        result = NoteListResult.from_dict(data)
        assert len(result.list) == 2
        assert result.total_items == 2
        assert result.has_more is True
        assert result.limit == 10


class TestTokenInfo:
    """Test cases for TokenInfo model."""

    def test_from_dict(self):
        """Test creating TokenInfo from dict."""
        data = {
            "token": "access_token",
            "refresh_token": "refresh_token",
            "token_expire_at": 1704067200,
            "refresh_token_expire_at": 1704153600,
            "jti": "uuid-123",
        }
        token_info = TokenInfo.from_dict(data)
        assert token_info.token == "access_token"
        assert token_info.refresh_token == "refresh_token"
        assert token_info.token_expire_at == 1704067200


class TestUser:
    """Test cases for User model."""

    def test_from_dict(self):
        """Test creating User from dict."""
        data = {
            "data": {
                "uid": 12345,
                "cellphone": "13800138000",
                "nickname": "TestUser",
                "avatar": "https://example.com/avatar.jpg",
                "status": 1,
                "app_id": 3,
                "vip_info": {
                    "is_vip": True,
                    "surplus_days": 30,
                },
                "rights_info": {
                    "audio_duration_ms": 3600000,
                },
                "quota_info": {
                    "local_audio_quota": {
                        "remained_duration": 1800000,
                    },
                },
                "labs": {
                    "can_create_topics": True,
                },
                "create_time": 1609459200,
            },
        }
        user = User.from_dict(data["data"])
        assert user.uid == 12345
        assert user.nickname == "TestUser"
        assert user.is_vip is True
        assert user.surplus_days == 30
        assert user.can_create_topics is True


class TestKnowledge:
    """Test cases for Knowledge model."""

    def test_from_dict(self):
        """Test creating Knowledge from dict."""
        data = {
            "id": 123,
            "id_alias": "abc123",
            "uid": 456,
            "name": "My Knowledge Base",
            "description": "Test description",
            "cover": "https://example.com/cover.jpg",
            "avatar": "https://example.com/avatar.jpg",
            "creator": "CreatorName",
            "is_author": 1,
            "is_added": 1,
            "scope": "DEFAULT",
            "share_url": "https://example.com/share",
            "extend_data": {
                "get_note_count": 10,
                "subscribe_count": 5,
                "all_resource_count": 15,
            },
            "root_dir": {
                "id": 789,
            },
            "last_update_time_desc": "2 hours ago",
            "create_time": 1609459200,
            "share_info": {
                "share_mode": "CLOSED",
            },
            "config": {
                "supported_file_type": ["pdf", "docx"],
            },
        }
        kb = Knowledge.from_dict(data)
        assert kb.id == 123
        assert kb.id_alias == "abc123"
        assert kb.name == "My Knowledge Base"
        assert kb.is_author is True
        assert kb.note_count == 10


class TestKnowledgeListResult:
    """Test cases for KnowledgeListResult model."""

    def test_from_dict(self):
        """Test creating KnowledgeListResult from dict."""
        data = {
            "list": [
                {
                    "id": 1,
                    "id_alias": "kb1",
                    "name": "KB 1",
                    "uid": 100,
                    "creator": "User1",
                    "is_author": 1,
                    "share_url": "https://example.com/1",
                    "extend_data": {
                        "get_note_count": 5,
                        "subscribe_count": 0,
                        "all_resource_count": 5,
                    },
                    "root_dir": {"id": 10},
                },
            ],
            "count": 1,
            "has_more": False,
        }
        result = KnowledgeListResult.from_dict(data)
        assert len(result.list) == 1
        assert result.count == 1
        assert result.has_more is False


class TestLinkNoteDetail:
    """Test cases for LinkNoteDetail model."""

    def test_from_dict(self):
        """Test creating LinkNoteDetail from dict."""
        data = {
            "title": "AI Generated Title",
            "web_title": "Original Web Title",
            "content": "<html>...</html>",
            "url": "https://example.com/article",
            "has_content": True,
        }
        detail = LinkNoteDetail.from_dict(data)
        assert detail.title == "AI Generated Title"
        assert detail.web_title == "Original Web Title"
        assert detail.url == "https://example.com/article"


class TestUploadTokenResult:
    """Test cases for UploadTokenResult model."""

    def test_from_dict_new_upload(self):
        """Test creating UploadTokenResult for new upload."""
        data = {
            "is_uploaded": False,
            "file_id": "file123",
            "token_info": {
                "object_key": "obj_key",
                "put_sign_url": "https://oss.example.com/upload",
                "put_content_type": "audio/mp3",
                "put_md5": "md5hash",
                "get_url": "https://oss.example.com/file.mp3",
            },
        }
        result = UploadTokenResult.from_dict(data)
        assert result.is_uploaded is False
        assert result.file_id == "file123"
        assert result.token_info is not None

    def test_from_dict_already_uploaded(self):
        """Test creating UploadTokenResult for already uploaded file."""
        data = {
            "is_uploaded": True,
            "file_id": "file456",
            "image": {
                "path": "https://oss.example.com/existing.mp3",
            },
        }
        result = UploadTokenResult.from_dict(data)
        assert result.is_uploaded is True
        assert result.image_path == "https://oss.example.com/existing.mp3"


class TestProgressItem:
    """Test cases for ProgressItem model."""

    def test_from_dict(self):
        """Test creating ProgressItem from dict."""
        data = {
            "msg": "Processing...",
            "processName": "downloading",
            "processStatus": "in_progress",
        }
        item = ProgressItem.from_dict(data)
        assert item.msg == "Processing..."
        assert item.process_name == "downloading"
        assert item.process_status == "in_progress"


class TestNoteNewFields:
    """Test cases for new fields added to Note model."""

    def test_from_dict_with_version_and_display_status(self):
        """Test Note with version and display_status fields."""
        data = {
            "id": "note123",
            "title": "Test",
            "content": "Content",
            "version": 2,
            "display_status": 1,
            "prompt_template_id": "custom",
            "is_author": True,
            "edit_time": "2026-02-08 09:41:01",
            "topic_id": "2732516",
            "has_ai_processed": True,
            "status": 0,
        }
        note = Note.from_dict(data)
        assert note.version == 2
        assert note.display_status == 1
        assert note.prompt_template_id == "custom"
        assert note.is_author is True
        assert note.edit_time == "2026-02-08 09:41:01"
        assert note.topic_id == "2732516"
        assert note.has_ai_processed is True


class TestDirectory:
    """Test cases for Directory model."""

    def test_from_dict(self):
        """Test creating Directory from dict."""
        data = {
            "id": 120,
            "topic_id": 35,
            "parent_id": 0,
            "name": "默认目录",
            "type": "ROOT",
            "resource_desc": "10 个内容",
            "create_time": 1769085177,
            "update_time": 1769432041,
        }
        d = Directory.from_dict(data)
        assert d.id == 120
        assert d.topic_id == 35
        assert d.parent_id == 0
        assert d.name == "默认目录"
        assert d.type == "ROOT"
        assert d.resource_desc == "10 个内容"


class TestFileMetaData:
    """Test cases for FileMetaData model."""

    def test_from_dict(self):
        """Test creating FileMetaData from dict."""
        data = {
            "name": "test.pdf",
            "type": "PDF",
            "source_type": "PDF",
            "file_url": "https://cdn.example.com/test.pdf",
            "source_file_url": "https://cdn.example.com/test.pdf",
            "storage_size": 1921069,
            "md5": "7f2daec3a2e1b8e5",
            "cover": "https://cdn.example.com/cover.jpeg",
        }
        f = FileMetaData.from_dict(data)
        assert f.name == "test.pdf"
        assert f.type == "PDF"
        assert f.storage_size == 1921069
        assert f.md5 == "7f2daec3a2e1b8e5"


class TestResource:
    """Test cases for Resource model."""

    def test_from_dict_note_type(self):
        """Test creating NOTE type Resource from dict."""
        data = {
            "id": 52488057,
            "uid": 1001534,
            "topic_id": 2732516,
            "topic_id_alias": "BJ8lRyAJ",
            "directory_id": 3276029,
            "resource_type": "NOTE",
            "resource_note_meta_data": {
                "id": "123",
                "title": "Test Note",
            },
            "resource_file_meta_data": None,
            "progress": "SUCCESS",
            "platform": "VOLC",
            "create_time": 1769432041,
        }
        r = Resource.from_dict(data)
        assert r.id == 52488057
        assert r.resource_type == "NOTE"
        assert r.resource_note_meta_data is not None
        assert r.resource_file_meta_data is None

    def test_from_dict_file_type(self):
        """Test creating FILE type Resource from dict."""
        data = {
            "id": 46940585,
            "uid": 36043,
            "topic_id": 35,
            "topic_id_alias": "lG0Prnaj",
            "directory_id": 2850263,
            "resource_type": "FILE",
            "resource_file_meta_data": {
                "name": "test.pdf",
                "type": "PDF",
                "file_url": "https://cdn.example.com/test.pdf",
                "source_file_url": "https://cdn.example.com/test.pdf",
                "storage_size": 1921069,
                "md5": "abc123",
            },
            "resource_note_meta_data": None,
            "progress": "SUCCESS",
        }
        r = Resource.from_dict(data)
        assert r.resource_type == "FILE"
        assert r.resource_file_meta_data is not None
        assert r.resource_file_meta_data.name == "test.pdf"
        assert r.resource_note_meta_data is None


class TestResourceListResult:
    """Test cases for ResourceListResult model."""

    def test_from_dict(self):
        """Test creating ResourceListResult from dict."""
        data = {
            "has_next": 1,
            "current_directory": {
                "id": 120,
                "topic_id": 35,
                "parent_id": 0,
                "name": "默认目录",
                "type": "ROOT",
            },
            "directories": [
                {"id": 140, "topic_id": 35, "parent_id": 120, "name": "子目录", "type": "DEFAULT"},
            ],
            "resources": [
                {
                    "id": 1,
                    "uid": 100,
                    "topic_id": 35,
                    "topic_id_alias": "abc",
                    "directory_id": 120,
                    "resource_type": "NOTE",
                },
            ],
        }
        result = ResourceListResult.from_dict(data)
        assert result.has_next is True
        assert result.current_directory is not None
        assert result.current_directory.name == "默认目录"
        assert len(result.directories) == 1
        assert len(result.resources) == 1

    def test_from_dict_empty(self):
        """Test ResourceListResult with null directories/resources."""
        data = {
            "has_next": 0,
            "current_directory": None,
            "directories": None,
            "resources": None,
        }
        result = ResourceListResult.from_dict(data)
        assert result.has_next is False
        assert result.current_directory is None
        assert len(result.directories) == 0
        assert len(result.resources) == 0


class TestFollowItem:
    """Test cases for FollowItem model."""

    def test_from_dict(self):
        """Test creating FollowItem from dict."""
        data = {
            "id": 100,
            "uid": 36043,
            "topic_id": 35,
            "type": 2,
            "name": "Test Live Stream",
            "platform": "DEDAO",
            "status": 2,
            "ai_status": 2,
            "create_time": 1769432041,
        }
        item = FollowItem.from_dict(data)
        assert item.id == 100
        assert item.type == 2
        assert item.name == "Test Live Stream"
        assert item.platform == "DEDAO"


class TestFollowListResult:
    """Test cases for FollowListResult model."""

    def test_from_dict(self):
        """Test creating FollowListResult from dict."""
        data = {
            "has_next": True,
            "list": [
                {"id": 1, "uid": 100, "topic_id": 35, "type": 2, "name": "Live 1"},
                {"id": 2, "uid": 100, "topic_id": 35, "type": 2, "name": "Live 2"},
            ],
        }
        result = FollowListResult.from_dict(data)
        assert result.has_next is True
        assert len(result.list) == 2


class TestLiveStreamPost:
    """Test cases for LiveStreamPost model."""

    def test_from_dict(self):
        """Test creating LiveStreamPost from dict."""
        data = {
            "post_id": 123456,
            "post_id_str": "123456",
            "post_id_alias": "abc",
            "post_name": "Test Live",
            "post_type": 4,
            "post_cover": "https://example.com/cover.jpg",
            "post_title": "Test Title",
            "post_summary": "# AI Summary\nContent here",
            "post_cleaned_summary": "AI Summary\nContent here",
            "post_url": "https://dedao.cn/live/detail/123",
            "ai_status": 2,
            "post_create_time": 1769432041,
        }
        post = LiveStreamPost.from_dict(data)
        assert post.post_id == 123456
        assert post.post_type == 4
        assert post.post_summary == "# AI Summary\nContent here"
        assert post.ai_status == 2


class TestChildrenCountResult:
    """Test cases for ChildrenCountResult model."""

    def test_from_dict(self):
        """Test creating ChildrenCountResult from dict."""
        data = {
            "total": 5,
            "can_add_child_note": True,
            "max_child_note_count": 30,
        }
        result = ChildrenCountResult.from_dict(data)
        assert result.total == 5
        assert result.can_add_child_note is True
        assert result.max_child_note_count == 30


class TestQuotaInfo:
    """Test cases for QuotaInfo model."""

    def test_get_remained_duration(self):
        """Test getting remaining audio duration."""
        quota = QuotaInfo(local_audio_quota={"remained_duration": 1800000})
        assert quota.get_remained_duration() == 1800000

    def test_get_remained_duration_missing(self):
        """Test getting remaining duration when key is missing."""
        quota = QuotaInfo(local_audio_quota={})
        assert quota.get_remained_duration() == 0


class TestAudioSectionInfo:
    """Test cases for AudioSectionInfo model."""

    def test_from_dict(self):
        """Test creating AudioSectionInfo from dict."""
        data = {
            "title": "Chapter 1",
            "description": "Introduction",
            "timestamp": "00:01:00",
            "milliseconds": 60000,
        }
        section = AudioSectionInfo.from_dict(data)
        assert section.title == "Chapter 1"
        assert section.description == "Introduction"
        assert section.timestamp == "00:01:00"
        assert section.milliseconds == 60000

    def test_from_dict_defaults(self):
        """Test AudioSectionInfo from_dict with missing keys."""
        section = AudioSectionInfo.from_dict({})
        assert section.title == ""
        assert section.description == ""
        assert section.timestamp == ""
        assert section.milliseconds == 0


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
