"""Tests for type definitions."""

import pytest

from toothfairyai.types import (
    Agent,
    AgentFunction,
    AgentResponse,
    Chat,
    CustomCodeExecutionEnvironment,
    CustomExecutionEnvironment,
    DatabaseConnection,
    Document,
    Entity,
    FileUploadResult,
    Folder,
    FolderTreeNode,
    Hosting,
    Message,
    Prompt,
    ScheduledJob,
    CronSchedule,
    CronExecutionConfig,
    CronNotificationConfig,
    CronRetryConfig,
    get_content_type,
)


class TestChatTypes:
    """Tests for chat-related types."""

    def test_chat_from_dict(self):
        """Test Chat.from_dict conversion."""
        data = {
            "id": "chat-123",
            "name": "Test Chat",
            "primaryRole": "user",
            "customerId": "customer-456",
            "customerInfo": {"name": "John"},
            "isAIReplying": True,
            "channelSettings": {"channel": "web", "provider": "default"},
        }
        chat = Chat.from_dict(data)

        assert chat.id == "chat-123"
        assert chat.name == "Test Chat"
        assert chat.primary_role == "user"
        assert chat.customer_id == "customer-456"
        assert chat.customer_info == {"name": "John"}
        assert chat.is_ai_replying is True
        assert chat.channel_settings is not None
        assert chat.channel_settings.channel == "web"

    def test_chat_from_dict_with_missing_fields(self):
        """Test Chat.from_dict with missing fields."""
        data = {"id": "chat-123"}
        chat = Chat.from_dict(data)

        assert chat.id == "chat-123"
        assert chat.name == ""
        assert chat.customer_info == {}
        assert chat.channel_settings is None

    def test_message_from_dict(self):
        """Test Message.from_dict conversion."""
        data = {
            "id": "msg-123",
            "chatID": "chat-456",
            "text": "Hello world",
            "role": "user",
            "userID": "user-789",
            "images": ["image1.jpg"],
        }
        message = Message.from_dict(data)

        assert message.id == "msg-123"
        assert message.chat_id == "chat-456"
        assert message.text == "Hello world"
        assert message.role == "user"
        assert message.images == ["image1.jpg"]


class TestDocumentTypes:
    """Tests for document-related types."""

    def test_document_from_dict(self):
        """Test Document.from_dict conversion."""
        data = {
            "id": "doc-123",
            "workspaceid": "ws-456",
            "userid": "user-789",
            "type": "readComprehensionPdf",
            "title": "Test Document",
            "topics": ["topic1", "topic2"],
            "folderid": "folder-123",
            "status": "published",
        }
        doc = Document.from_dict(data)

        assert doc.id == "doc-123"
        assert doc.workspace_id == "ws-456"
        assert doc.doc_type == "readComprehensionPdf"
        assert doc.title == "Test Document"
        assert doc.topics == ["topic1", "topic2"]

    def test_file_upload_result_from_dict(self):
        """Test FileUploadResult.from_dict conversion."""
        data = {
            "success": True,
            "originalFilename": "test.pdf",
            "sanitizedFilename": "test.pdf",
            "filename": "uuid-test.pdf",
            "importType": "file",
            "contentType": "application/pdf",
            "size": 1024,
            "sizeInMB": 0.001,
        }
        result = FileUploadResult.from_dict(data)

        assert result.success is True
        assert result.original_filename == "test.pdf"
        assert result.content_type == "application/pdf"
        assert result.size == 1024


class TestEntityTypes:
    """Tests for entity-related types."""

    def test_entity_from_dict(self):
        """Test Entity.from_dict conversion."""
        data = {
            "id": "entity-123",
            "workspaceid": "ws-456",
            "createdBy": "user-789",
            "label": "Dental Cleaning",
            "type": "topic",
            "description": "Professional cleaning",
            "emoji": "🦷",
        }
        entity = Entity.from_dict(data)

        assert entity.id == "entity-123"
        assert entity.label == "Dental Cleaning"
        assert entity.entity_type == "topic"
        assert entity.emoji == "🦷"


class TestFolderTypes:
    """Tests for folder-related types."""

    def test_folder_from_dict(self):
        """Test Folder.from_dict conversion."""
        data = {
            "id": "folder-123",
            "workspaceID": "ws-456",
            "createdBy": "user-789",
            "name": "Documents",
            "description": "Main documents folder",
            "status": "active",
            "parent": None,
        }
        folder = Folder.from_dict(data)

        assert folder.id == "folder-123"
        assert folder.name == "Documents"
        assert folder.status == "active"
        assert folder.parent is None

    def test_folder_tree_node_from_folder(self):
        """Test FolderTreeNode.from_folder conversion."""
        folder = Folder(
            id="folder-123",
            workspace_id="ws-456",
            created_by="user-789",
            name="Parent",
        )
        children = []
        node = FolderTreeNode.from_folder(folder, children)

        assert node.id == "folder-123"
        assert node.name == "Parent"
        assert node.children == []


class TestPromptTypes:
    """Tests for prompt-related types."""

    def test_prompt_from_dict(self):
        """Test Prompt.from_dict conversion."""
        data = {
            "id": "prompt-123",
            "workspaceID": "ws-456",
            "createdBy": "user-789",
            "type": "greeting",
            "label": "Welcome Prompt",
            "promptLength": 50,
            "interpolationString": "Hello {{name}}!",
            "availableToAgents": ["agent-1", "agent-2"],
        }
        prompt = Prompt.from_dict(data)

        assert prompt.id == "prompt-123"
        assert prompt.label == "Welcome Prompt"
        assert prompt.prompt_type == "greeting"
        assert prompt.interpolation_string == "Hello {{name}}!"
        assert prompt.available_to_agents == ["agent-1", "agent-2"]


class TestUtilityFunctions:
    """Tests for utility functions."""

    def test_get_content_type_pdf(self):
        """Test content type detection for PDF."""
        assert get_content_type("document.pdf") == "application/pdf"

    def test_get_content_type_image(self):
        """Test content type detection for images."""
        assert get_content_type("image.jpg") == "image/jpeg"
        assert get_content_type("image.jpeg") == "image/jpeg"
        assert get_content_type("image.png") == "image/png"

    def test_get_content_type_unknown(self):
        """Test content type detection for unknown extension."""
        assert get_content_type("file.xyz") == "application/octet-stream"

    def test_get_content_type_case_insensitive(self):
        """Test that content type detection is case insensitive."""
        assert get_content_type("document.PDF") == "application/pdf"
        assert get_content_type("image.JPG") == "image/jpeg"


class TestAgentTypes:
    """Tests for Agent type with all fields."""

    def test_agent_from_dict_basic(self):
        """Test Agent.from_dict with basic fields."""
        data = {
            "id": "agent-123",
            "workspaceID": "ws-456",
            "label": "Test Agent",
            "description": "A test agent",
            "goals": "Help users",
        }
        agent = Agent.from_dict(data)

        assert agent.id == "agent-123"
        assert agent.workspace_id == "ws-456"
        assert agent.label == "Test Agent"
        assert agent.description == "A test agent"
        assert agent.goals == "Help users"

    def test_agent_from_dict_with_llm_settings(self):
        """Test Agent.from_dict with LLM settings."""
        data = {
            "id": "agent-123",
            "workspaceID": "ws-456",
            "label": "Test Agent",
            "llmEndpoint": "https://api.openai.com",
            "llmUrl": "https://api.openai.com/v1",
            "llmUrlStatus": "ready",
            "llmUrlType": "serverless",
            "llmBaseModel": "gpt-4",
            "llmProvider": "openai",
            "llmTopK": 40.0,
            "llmSeed": 42.0,
        }
        agent = Agent.from_dict(data)

        assert agent.llm_endpoint == "https://api.openai.com"
        assert agent.llm_url == "https://api.openai.com/v1"
        assert agent.llm_url_status == "ready"
        assert agent.llm_url_type == "serverless"
        assert agent.llm_base_model == "gpt-4"
        assert agent.llm_provider == "openai"
        assert agent.llm_top_k == 40.0
        assert agent.llm_seed == 42.0

    def test_agent_from_dict_with_reasoning_settings(self):
        """Test Agent.from_dict with reasoning settings."""
        data = {
            "id": "agent-123",
            "workspaceID": "ws-456",
            "label": "Test Agent",
            "agentType": "Chatbot",
            "reasoningMode": "auto",
            "reasoningEffort": "high",
            "fnReasoningEffort": "medium",
            "reasoningBudget": 1000,
        }
        agent = Agent.from_dict(data)

        assert agent.agent_type == "Chatbot"
        assert agent.reasoning_mode == "auto"
        assert agent.reasoning_effort == "high"
        assert agent.fn_reasoning_effort == "medium"
        assert agent.reasoning_budget == 1000

    def test_agent_from_dict_with_voice_settings(self):
        """Test Agent.from_dict with voice settings."""
        data = {
            "id": "agent-123",
            "workspaceID": "ws-456",
            "label": "Test Agent",
            "voiceName": "alloy",
            "sttModel": "whisper-1",
            "ttsModel": "tts-1",
            "llmVoiceModel": "gpt-4-audio",
            "defaultVoiceLanguage": "en-US",
            "voiceMinSilenceDuration": 0.5,
            "voiceMinEndpointingDelay": 1.0,
            "voiceMinInterruptionDuration": 0.3,
            "enableVoiceIntermissions": True,
            "voiceBackgroundNoise": "none",
            "autoVoiceMode": True,
            "voiceSensitivity": "high",
        }
        agent = Agent.from_dict(data)

        assert agent.voice_name == "alloy"
        assert agent.stt_model == "whisper-1"
        assert agent.tts_model == "tts-1"
        assert agent.llm_voice_model == "gpt-4-audio"
        assert agent.default_voice_language == "en-US"
        assert agent.voice_min_silence_duration == 0.5
        assert agent.voice_min_endpointing_delay == 1.0
        assert agent.voice_min_interruption_duration == 0.3
        assert agent.enable_voice_intermissions is True
        assert agent.auto_voice_mode is True

    def test_agent_from_dict_with_planning_settings(self):
        """Test Agent.from_dict with planning settings."""
        data = {
            "id": "agent-123",
            "workspaceID": "ws-456",
            "label": "Test Agent",
            "agentsPool": ["agent-1", "agent-2"],
            "mcps": ["mcp-1"],
            "maxPlanningSteps": 10,
            "maxBrowserSteps": 5,
            "planningInstructions": "Plan carefully",
            "plannerExecutionAttempts": 3,
            "plannerRequiresApprovalForPlanExecution": True,
            "plannerEmailOnApprovalRequest": True,
            "plannerApproverEmails": ["admin@example.com"],
            "allowReplanning": True,
        }
        agent = Agent.from_dict(data)

        assert agent.agents_pool == ["agent-1", "agent-2"]
        assert agent.mcps == ["mcp-1"]
        assert agent.max_planning_steps == 10
        assert agent.max_browser_steps == 5
        assert agent.planning_instructions == "Plan carefully"
        assert agent.planner_requires_approval_for_plan_execution is True
        assert agent.planner_approver_emails == ["admin@example.com"]

    def test_agent_from_dict_with_upload_generation_settings(self):
        """Test Agent.from_dict with upload/generation settings."""
        data = {
            "id": "agent-123",
            "workspaceID": "ws-456",
            "label": "Test Agent",
            "allowImagesUpload": True,
            "allowVideosUpload": False,
            "allowAudiosUpload": True,
            "allowDocsUpload": True,
            "allowImagesGeneration": True,
            "baseImageGenerationModel": "dall-e-3",
            "maxImagesGenerated": 4,
            "advancedImageGeneration": True,
            "allowVideosGeneration": False,
            "allow3dModelGeneration": False,
            "allowIntrospection": True,
        }
        agent = Agent.from_dict(data)

        assert agent.allow_images_upload is True
        assert agent.allow_videos_upload is False
        assert agent.allow_audios_upload is True
        assert agent.allow_docs_upload is True
        assert agent.allow_images_generation is True
        assert agent.base_image_generation_model == "dall-e-3"
        assert agent.max_images_generated == 4
        assert agent.advanced_image_generation is True
        assert agent.allow_introspection is True

    def test_agent_from_dict_with_sip_settings(self):
        """Test Agent.from_dict with SIP settings."""
        data = {
            "id": "agent-123",
            "workspaceID": "ws-456",
            "label": "Test Agent",
            "sipPhoneNumber": "+1234567890",
            "sipDispatchRuleId": "rule-123",
            "enableInboundSip": True,
            "enableOutboundSip": False,
        }
        agent = Agent.from_dict(data)

        assert agent.sip_phone_number == "+1234567890"
        assert agent.sip_dispatch_rule_id == "rule-123"
        assert agent.enable_inbound_sip is True
        assert agent.enable_outbound_sip is False

    def test_agent_from_dict_with_rag_settings(self):
        """Test Agent.from_dict with RAG settings."""
        data = {
            "id": "agent-123",
            "workspaceID": "ws-456",
            "label": "Test Agent",
            "agenticRAG": True,
            "reRank": True,
            "ragSearchStrategy": "parallel",
            "minChunksBeforeCompleteness": 0.5,
            "ragCompletenessThreshold": 0.8,
            "ragInstructions": "Search thoroughly",
            "keywordsWeightInRetrieval": 0.3,
        }
        agent = Agent.from_dict(data)

        assert agent.agentic_rag is True
        assert agent.re_rank is True
        assert agent.rag_search_strategy == "parallel"
        assert agent.min_chunks_before_completeness == 0.5
        assert agent.rag_completeness_threshold == 0.8
        assert agent.rag_instructions == "Search thoroughly"


class TestAgentFunctionTypes:
    """Tests for AgentFunction type with all fields."""

    def test_agent_function_from_dict_basic(self):
        """Test AgentFunction.from_dict with basic fields."""
        data = {
            "id": "fn-123",
            "name": "Test Function",
            "description": "A test function",
            "workspaceID": "ws-456",
            "url": "https://api.example.com/execute",
            "requestType": "post",
            "authorisationType": "bearer",
        }
        fn = AgentFunction.from_dict(data)

        assert fn.id == "fn-123"
        assert fn.name == "Test Function"
        assert fn.description == "A test function"
        assert fn.url == "https://api.example.com/execute"
        assert fn.request_type == "post"
        assert fn.authorisation_type == "bearer"

    def test_agent_function_from_dict_with_skill_settings(self):
        """Test AgentFunction.from_dict with agent skill settings."""
        data = {
            "id": "fn-123",
            "name": "Skill Function",
            "description": "An agent skill",
            "isAgentSkill": True,
            "agentSkillScript": "def execute(): return 'result'",
            "codeExecutionEnvironmentID": "env-123",
        }
        fn = AgentFunction.from_dict(data)

        assert fn.is_agent_skill is True
        assert fn.agent_skill_script == "def execute(): return 'result'"
        assert fn.code_execution_environment_id == "env-123"

    def test_agent_function_from_dict_with_handoff_settings(self):
        """Test AgentFunction.from_dict with handoff settings."""
        data = {
            "id": "fn-123",
            "name": "Handoff Function",
            "description": "A handoff function",
            "isHandOffFn": True,
            "handOffAgent": "agent-456",
            "handOffToOriginalAgentOnCompletion": True,
            "handOffToOriginalAgentOnFailure": False,
            "handOffAgentOnCompletion": "agent-789",
            "handOffAgentOnFailure": "agent-error",
            "usersToHandOffTo": ["user-1", "user-2"],
            "handedOffToHumanOnCall": True,
        }
        fn = AgentFunction.from_dict(data)

        assert fn.is_hand_off_fn is True
        assert fn.hand_off_agent == "agent-456"
        assert fn.hand_off_to_original_agent_on_completion is True
        assert fn.hand_off_to_original_agent_on_failure is False
        assert fn.hand_off_agent_on_completion == "agent-789"
        assert fn.users_to_hand_off_to == ["user-1", "user-2"]
        assert fn.handed_off_to_human_on_call is True

    def test_agent_function_from_dict_with_chat_settings(self):
        """Test AgentFunction.from_dict with chat settings."""
        data = {
            "id": "fn-123",
            "name": "Chat Function",
            "description": "A chat function",
            "isChatFn": True,
            "chatScript": "async def chat(message): return 'response'",
            "chatAction": "suggestion",
        }
        fn = AgentFunction.from_dict(data)

        assert fn.is_chat_fn is True
        assert fn.chat_script == "async def chat(message): return 'response'"
        assert fn.chat_action == "suggestion"

    def test_agent_function_from_dict_with_html_settings(self):
        """Test AgentFunction.from_dict with HTML settings."""
        data = {
            "id": "fn-123",
            "name": "HTML Function",
            "description": "An HTML function",
            "isHtmlFn": True,
            "htmlUrl": "https://example.com/form",
            "htmlScript": "<form>...</form>",
            "isHtmlRedirectFn": False,
            "htmlFormOnSuccessfulSubmitMessage": "Success!",
            "htmlFormOnFailedSubmitMessage": "Error!",
        }
        fn = AgentFunction.from_dict(data)

        assert fn.is_html_fn is True
        assert fn.html_url == "https://example.com/form"
        assert fn.html_script == "<form>...</form>"
        assert fn.is_html_redirect_fn is False
        assert fn.html_form_on_successful_submit_message == "Success!"

    def test_agent_function_from_dict_with_database_settings(self):
        """Test AgentFunction.from_dict with database settings."""
        data = {
            "id": "fn-123",
            "name": "Database Function",
            "description": "A database function",
            "isDatabaseScript": True,
            "dbScript": "SELECT * FROM users",
            "dbConnectionID": "db-123",
            "dbSchemaMetadata": {"table": "users"},
            "preExecutionScript": "SET search_path = public",
            "postExecutionScript": "COMMIT",
        }
        fn = AgentFunction.from_dict(data)

        assert fn.is_database_script is True
        assert fn.db_script == "SELECT * FROM users"
        assert fn.db_connection_id == "db-123"
        assert fn.db_schema_metadata == {"table": "users"}
        assert fn.pre_execution_script == "SET search_path = public"

    def test_agent_function_from_dict_with_mcp_settings(self):
        """Test AgentFunction.from_dict with MCP settings."""
        data = {
            "id": "fn-123",
            "name": "MCP Server",
            "description": "An MCP server",
            "isMCPServer": True,
            "scope": "customer",
            "jsonPathExtractor": "$.data",
            "dependsOnBeforeExecution": ["fn-1"],
            "dependsOnAfterExecution": ["fn-2"],
        }
        fn = AgentFunction.from_dict(data)

        assert fn.is_mcp_server is True
        assert fn.scope == "customer"
        assert fn.json_path_extractor == "$.data"
        assert fn.depends_on_before_execution == ["fn-1"]
        assert fn.depends_on_after_execution == ["fn-2"]

    def test_agent_function_from_dict_with_graphql_settings(self):
        """Test AgentFunction.from_dict with GraphQL settings."""
        data = {
            "id": "fn-123",
            "name": "GraphQL Function",
            "description": "A GraphQL function",
            "requestType": "graphql_query",
            "graphqlQuery": "{ users { id name } }",
            "graphqlMutation": None,
            "graphqlOperationName": "GetUsers",
        }
        fn = AgentFunction.from_dict(data)

        assert fn.request_type == "graphql_query"
        assert fn.graphql_query == "{ users { id name } }"
        assert fn.graphql_operation_name == "GetUsers"


class TestCustomCodeExecutionEnvironmentTypes:
    """Tests for CustomCodeExecutionEnvironment (Hook) type."""

    def test_custom_code_execution_environment_from_dict(self):
        """Test CustomCodeExecutionEnvironment.from_dict."""
        data = {
            "id": "hook-123",
            "name": "Test Hook",
            "workspaceID": "ws-456",
            "description": "A test hook",
            "functionName": "execute",
            "customExecutionCode": "def execute(): pass",
            "customExecutionInstructions": "Run this code",
            "customExecutionSecrets": {"api_key": "secret"},
            "staticDocs": {"doc1": "content"},
            "availableLibraries": "numpy, pandas",
            "allowExternalAPI": True,
            "hardcodedScript": False,
            "isTemplate": False,
            "createdBy": "user-123",
            "updatedBy": "user-456",
        }
        hook = CustomCodeExecutionEnvironment.from_dict(data)

        assert hook.id == "hook-123"
        assert hook.name == "Test Hook"
        assert hook.workspace_id == "ws-456"
        assert hook.function_name == "execute"
        assert hook.custom_execution_code == "def execute(): pass"
        assert hook.custom_execution_secrets == {"api_key": "secret"}
        assert hook.static_docs == {"doc1": "content"}
        assert hook.allow_external_api is True
        assert hook.is_template is False
        assert hook.created_by == "user-123"
        assert hook.updated_by == "user-456"


class TestCustomExecutionEnvironmentTypes:
    """Tests for CustomExecutionEnvironment type."""

    def test_custom_execution_environment_from_dict(self):
        """Test CustomExecutionEnvironment.from_dict."""
        data = {
            "id": "env-123",
            "name": "Remote Environment",
            "workspaceID": "ws-456",
            "description": "A remote execution environment",
            "functionName": "run_remote",
            "availableLibraries": "requests, httpx",
            "ip": "192.168.1.100",
            "port": "8080",
            "metadata": {"region": "us-east-1"},
            "isGlobal": False,
            "createdBy": "user-123",
        }
        env = CustomExecutionEnvironment.from_dict(data)

        assert env.id == "env-123"
        assert env.name == "Remote Environment"
        assert env.ip == "192.168.1.100"
        assert env.port == "8080"
        assert env.metadata == {"region": "us-east-1"}
        assert env.is_global is False


class TestScheduledJobTypes:
    """Tests for ScheduledJob (CronJob) type with nested types."""

    def test_cron_schedule_from_dict(self):
        """Test CronSchedule.from_dict."""
        data = {
            "frequency": "DAILY",
            "interval": 1,
            "cronExpression": None,
            "dayOfWeek": None,
            "dayOfMonth": None,
            "hour": 9,
            "minute": 30,
            "startDate": "2024-01-01T00:00:00Z",
            "endDate": "2024-12-31T23:59:59Z",
        }
        schedule = CronSchedule.from_dict(data)

        assert schedule.frequency == "DAILY"
        assert schedule.interval == 1
        assert schedule.hour == 9
        assert schedule.minute == 30
        assert schedule.start_date == "2024-01-01T00:00:00Z"

    def test_cron_execution_config_from_dict(self):
        """Test CronExecutionConfig.from_dict."""
        data = {
            "timeout": 300,
            "maxDuration": 600,
            "priority": "HIGH",
            "inputParameters": {"key": "value"},
            "outputFormat": "json",
            "webhookUrl": "https://example.com/webhook",
            "webhookHeaders": {"Authorization": "Bearer token"},
        }
        config = CronExecutionConfig.from_dict(data)

        assert config.timeout == 300
        assert config.max_duration == 600
        assert config.priority == "HIGH"
        assert config.input_parameters == {"key": "value"}
        assert config.webhook_url == "https://example.com/webhook"

    def test_cron_notification_config_from_dict(self):
        """Test CronNotificationConfig.from_dict."""
        data = {
            "onSuccess": True,
            "onFailure": True,
            "onStart": False,
            "emailRecipients": ["admin@example.com", "ops@example.com"],
            "communicationServiceID": "svc-123",
        }
        config = CronNotificationConfig.from_dict(data)

        assert config.on_success is True
        assert config.on_failure is True
        assert config.on_start is False
        assert config.email_recipients == ["admin@example.com", "ops@example.com"]
        assert config.communication_service_id == "svc-123"

    def test_cron_retry_config_from_dict(self):
        """Test CronRetryConfig.from_dict."""
        data = {
            "maxRetries": 5,
            "retryInterval": 120,
            "backoffMultiplier": 2.0,
            "maxRetryInterval": 3600,
        }
        config = CronRetryConfig.from_dict(data)

        assert config.max_retries == 5
        assert config.retry_interval == 120
        assert config.backoff_multiplier == 2.0
        assert config.max_retry_interval == 3600

    def test_scheduled_job_from_dict_with_nested_types(self):
        """Test ScheduledJob.from_dict with nested configuration types."""
        data = {
            "id": "job-123",
            "name": "Daily Report",
            "workspaceID": "ws-456",
            "description": "Generate daily report",
            "agentID": "agent-789",
            "customPromptID": "prompt-123",
            "forcedPrompt": "Generate report for {{date}}",
            "timezone": "America/New_York",
            "isActive": True,
            "lastRunAt": "2024-01-01T09:00:00Z",
            "nextRunAt": "2024-01-02T09:00:00Z",
            "status": "ACTIVE",
            "schedule": {
                "frequency": "DAILY",
                "hour": 9,
                "minute": 0,
            },
            "executionConfig": {
                "timeout": 300,
                "priority": "MEDIUM",
            },
            "notificationConfig": {
                "onSuccess": True,
                "emailRecipients": ["admin@example.com"],
            },
            "retryConfig": {
                "maxRetries": 3,
            },
            "metadata": {"tags": ["daily", "report"]},
            "createdBy": "user-123",
            "updatedBy": "user-456",
            "createdAt": "2024-01-01T00:00:00Z",
            "updatedAt": "2024-01-01T12:00:00Z",
        }
        job = ScheduledJob.from_dict(data)

        assert job.id == "job-123"
        assert job.name == "Daily Report"
        assert job.workspace_id == "ws-456"
        assert job.agent_id == "agent-789"
        assert job.custom_prompt_id == "prompt-123"
        assert job.timezone == "America/New_York"
        assert job.is_active is True
        assert job.status == "ACTIVE"
        assert job.schedule is not None
        assert job.schedule.frequency == "DAILY"
        assert job.schedule.hour == 9
        assert job.execution_config is not None
        assert job.execution_config.timeout == 300
        assert job.notification_config is not None
        assert job.notification_config.on_success is True
        assert job.retry_config is not None
        assert job.retry_config.max_retries == 3
        assert job.metadata == {"tags": ["daily", "report"]}

    def test_scheduled_job_from_dict_minimal(self):
        """Test ScheduledJob.from_dict with minimal data."""
        data = {
            "id": "job-123",
            "name": "Simple Job",
        }
        job = ScheduledJob.from_dict(data)

        assert job.id == "job-123"
        assert job.name == "Simple Job"
        assert job.timezone == "UTC"
        assert job.status == "PENDING"
        assert job.schedule is None
        assert job.execution_config is None
        assert job.notification_config is None


class TestHostingTypes:
    """Tests for Hosting (Connection) type."""

    def test_hosting_from_dict(self):
        """Test Hosting.from_dict."""
        data = {
            "id": "hosting-123",
            "name": "OpenAI Connection",
            "type": "openai",
            "workspaceID": "ws-456",
            "description": "OpenAI API connection",
            "tokenSecret": "openai-api-key",
            "endpoint": "https://api.openai.com",
            "modelName": "gpt-4",
            "baseModel": "gpt-4",
            "customModel": False,
            "apiVersion": "v1",
            "createdBy": "user-123",
            "updatedBy": "user-456",
        }
        hosting = Hosting.from_dict(data)

        assert hosting.id == "hosting-123"
        assert hosting.name == "OpenAI Connection"
        assert hosting.type == "openai"
        assert hosting.endpoint == "https://api.openai.com"
        assert hosting.model_name == "gpt-4"
        assert hosting.custom_model is False
        assert hosting.api_version == "v1"


class TestDatabaseConnectionTypes:
    """Tests for DatabaseConnection type."""

    def test_database_connection_from_dict(self):
        """Test DatabaseConnection.from_dict."""
        data = {
            "id": "db-123",
            "name": "Postgres Database",
            "type": "postgresql",
            "host": "db.example.com",
            "port": "5432",
            "username": "admin",
            "passwordSecret": "db-password",
            "database": "production",
            "workspaceID": "ws-456",
            "description": "Production database",
            "schema": "public",
            "ssl": True,
            "ssh": False,
            "createdBy": "user-123",
        }
        db = DatabaseConnection.from_dict(data)

        assert db.id == "db-123"
        assert db.name == "Postgres Database"
        assert db.type == "postgresql"
        assert db.host == "db.example.com"
        assert db.port == "5432"
        assert db.username == "admin"
        assert db.password_secret == "db-password"
        assert db.database == "production"
        assert db.ssl is True
        assert db.ssh is False


class TestPromptTypesExtended:
    """Extended tests for Prompt type."""

    def test_prompt_from_dict_with_all_fields(self):
        """Test Prompt.from_dict with all fields."""
        data = {
            "id": "prompt-123",
            "workspaceID": "ws-456",
            "type": "greeting",
            "label": "Welcome Prompt",
            "promptLength": 150,
            "interpolationString": "Hello {{name}}! Welcome to our service. We're here to help you.",
            "scope": "workspace",
            "style": "formal",
            "domain": "customerService",
            "promptPlaceholder": "Enter your name",
            "availableToAgents": ["agent-1", "agent-2"],
            "createdBy": "user-123",
            "updatedBy": "user-456",
            "createdAt": "2024-01-01T00:00:00Z",
            "updatedAt": "2024-01-02T00:00:00Z",
        }
        prompt = Prompt.from_dict(data)

        assert prompt.id == "prompt-123"
        assert prompt.prompt_type == "greeting"
        assert prompt.label == "Welcome Prompt"
        assert prompt.prompt_length == 150
        assert prompt.interpolation_string == "Hello {{name}}! Welcome to our service. We're here to help you."
        assert prompt.scope == "workspace"
        assert prompt.style == "formal"
        assert prompt.domain == "customerService"
        assert prompt.prompt_placeholder == "Enter your name"
        assert prompt.available_to_agents == ["agent-1", "agent-2"]
        assert prompt.created_by == "user-123"
        assert prompt.updated_by == "user-456"
