from __future__ import annotations

import unittest
from unittest.mock import MagicMock, patch

from apps import aroflo_connector_app as app
from apps.aroflo_connector_app.services.users_v1 import UsersContractError, query_users
from bridge_platform.agents.tool_catalog import manifest_tools


PAGE = {
    "status": "0",
    "zoneresponse": {"users": [
        {"userid": "u1", "givennames": "Carolina", "surname": "Penuela",
         "email": "carolina@example.test", "phone": "02 1111 2222",
         "mobile": "0400 111 222", "position": "Manager", "archived": "false"},
        {"userid": "u2", "givennames": "Caroline", "surname": "Smith",
         "email": "caroline@example.test", "phone": "02 3333 4444",
         "position": "Technician", "archived": "true"},
    ]},
}


class UsersContractChecks(unittest.TestCase):
    def test_composed_filters_return_normalized_user(self):
        client = MagicMock()
        client.request.side_effect = [PAGE, {"status": "0", "zoneresponse": {"users": []}}]
        result = query_users(client, {
            "operation": "search",
            "filters": [
                {"field": "display_name", "operator": "contains", "value": "Carolina Penuela"},
                {"field": "archived", "operator": "eq", "value": False},
            ],
            "pagination": {"page": 1, "page_size": 25},
        })
        self.assertEqual("Carolina Penuela", result["items"][0]["display_name"])
        self.assertEqual("02 1111 2222", result["items"][0]["phone"])
        self.assertNotIn("zoneresponse", str(result))
        self.assertEqual("api", result["meta"]["transport"])

    def test_unknown_filter_is_rejected_before_provider_call(self):
        client = MagicMock()
        with self.assertRaises(UsersContractError) as raised:
            query_users(client, {"operation": "search", "filters": [
                {"field": "raw_where", "operator": "eq", "value": "anything"},
            ]})
        self.assertEqual("unsupported_filter", raised.exception.code)
        client.request.assert_not_called()

    def test_get_uses_canonical_record_id(self):
        client = MagicMock()
        client.request.return_value = PAGE
        result = query_users(client, {"operation": "get", "record_id": "u2"})
        self.assertEqual("u2", result["item"]["user_id"])
        self.assertEqual([], result["items"])

    def test_manifest_exposes_three_specific_low_risk_tools(self):
        tools = {tool["capability"]: tool for tool in manifest_tools(app.APP_MANIFEST)}
        self.assertEqual(
            {"aroflo.users.list", "aroflo.users.get", "aroflo.users.search"},
            set(tools),
        )
        self.assertTrue(all(tool["risk"]["category"] == "read" for tool in tools.values()))
        self.assertTrue(all(tool["confirmation"] == "never" for tool in tools.values()))

    @patch("apps.aroflo_connector_app.SecretsManager")
    @patch("apps.aroflo_connector_app.AroFloClient")
    def test_standard_action_returns_normalized_envelope(self, client_class, manager_class):
        credentials = {
            "aroflo_base_url": "https://api.example.invalid",
            "aroflo_u_encoded": "user", "aroflo_p_encoded": "password",
            "aroflo_api_secret": "secret", "aroflo_org_encoded": "org",
        }
        manager_class.return_value.get_secret.side_effect = lambda **kwargs: credentials.get(kwargs["secret_name"])
        client_class.return_value.request.side_effect = [PAGE, {"status": "0", "zoneresponse": {"users": []}}]
        context = {"request_id": "req-users", "tenant": {"tenant_id": "tenant-a"}, "payload": {
            "filters": [{"field": "display_name", "operator": "contains", "value": "Carolina"}],
        }}
        result = app.handle_request(context, "users_search_v1")
        self.assertEqual("ok", result["status"])
        self.assertEqual("users", result["data"]["meta"]["zone"])
        self.assertEqual("Carolina Penuela", result["data"]["items"][0]["display_name"])


if __name__ == "__main__":
    unittest.main()
