import random

import pytest
from arthur_common.models.enums import RegisteredAgentProvider, RuleScope, RuleType
from arthur_common.models.request_schemas import AgentMetadata, GCPAgentMetadata

from db_models import DatabaseTask
from tests.clients.base_test_client import (
    GenaiEngineTestClientBase,
    override_get_db_session,
)


@pytest.mark.unit_tests
def test_user_story_create_task_get_task(client: GenaiEngineTestClientBase):
    task_name = str(random.random())
    client.create_rule("", rule_type=RuleType.REGEX)
    status_code, task_response = client.create_task(task_name)
    assert status_code == 200

    assert task_response.name == task_name
    assert task_response.is_agentic == False  # Default should be False

    status_code, task = client.get_task(task_response.id)

    assert len(task.rules) > 0
    assert task.is_agentic == False


@pytest.mark.unit_tests
def test_user_story_create_task_rule_update_rule(client: GenaiEngineTestClientBase):
    task_name = str(random.random())
    status_code, task_response = client.create_task(task_name, empty_rules=True)
    assert status_code == 200

    assert task_response.name == task_name

    custom_keyword = str(random.random())
    rule_name = str(random.random())
    status_code, task_scoped_keyword_rule = client.create_rule(
        rule_name,
        rule_type=RuleType.KEYWORD,
        keywords=[custom_keyword],
        task_id=task_response.id,
    )

    assert status_code == 200
    assert task_scoped_keyword_rule.scope == RuleScope.TASK

    status_code, _ = client.patch_rule(
        task_response.id,
        task_scoped_keyword_rule.id,
        False,
    )
    assert status_code == 200

    status_code, task = client.get_task(task_response.id)
    get_task_rules = task.rules
    assert len(get_task_rules) > 0
    # Assert patched rule is disabled
    patched_rule = [r for r in get_task_rules if r.id == task_scoped_keyword_rule.id][0]
    assert patched_rule.enabled == False


@pytest.mark.unit_tests
def test_create_agentic_task(client: GenaiEngineTestClientBase):
    """Test creating a task with is_agentic=True"""
    task_name = str(random.random())
    status_code, task_response = client.create_task(task_name, is_agentic=True)
    assert status_code == 200

    assert task_response.name == task_name
    assert task_response.is_agentic == True

    # Verify by getting the task
    status_code, task = client.get_task(task_response.id)
    assert status_code == 200
    assert task.is_agentic == True


@pytest.mark.unit_tests
def test_create_non_agentic_task_explicit(client: GenaiEngineTestClientBase):
    """Test creating a task with is_agentic=False explicitly"""
    task_name = str(random.random())
    status_code, task_response = client.create_task(task_name, is_agentic=False)
    assert status_code == 200

    assert task_response.name == task_name
    assert task_response.is_agentic == False

    # Verify by getting the task
    status_code, task = client.get_task(task_response.id)
    assert status_code == 200
    assert task.is_agentic == False


@pytest.mark.unit_tests
def test_search_tasks_by_agentic_status(client: GenaiEngineTestClientBase):
    """Test filtering tasks by agentic status"""
    # Create some agentic and non-agentic tasks
    agentic_task_ids = []
    non_agentic_task_ids = []

    for i in range(3):
        # Create agentic tasks
        status_code, task = client.create_task(f"agentic_task_{i}", is_agentic=True)
        assert status_code == 200
        agentic_task_ids.append(task.id)

        # Create non-agentic tasks
        status_code, task = client.create_task(
            f"non_agentic_task_{i}",
            is_agentic=False,
        )
        assert status_code == 200
        non_agentic_task_ids.append(task.id)

    # Search for agentic tasks only
    status_code, search_response = client.search_tasks(is_agentic=True, page_size=50)
    assert status_code == 200

    agentic_results = [
        task for task in search_response.tasks if task.id in agentic_task_ids
    ]
    assert len(agentic_results) == 3
    for task in agentic_results:
        assert task.is_agentic == True

    # Search for non-agentic tasks only
    status_code, search_response = client.search_tasks(is_agentic=False, page_size=50)
    assert status_code == 200

    non_agentic_results = [
        task for task in search_response.tasks if task.id in non_agentic_task_ids
    ]
    assert len(non_agentic_results) == 3
    for task in non_agentic_results:
        assert task.is_agentic == False

    # Search without filter should return both types
    status_code, search_response = client.search_tasks(page_size=50)
    assert status_code == 200

    all_test_tasks = [
        task
        for task in search_response.tasks
        if task.id in agentic_task_ids + non_agentic_task_ids
    ]
    assert len(all_test_tasks) == 6


@pytest.mark.unit_tests
def test_create_task_with_agent_metadata_stores_creation_source(
    client: GenaiEngineTestClientBase,
):
    """Test that creating a task with agent metadata stores GCP creation_source in task_metadata."""
    task_name = str(random.random())
    status_code, task_response = client.create_task(
        task_name,
        is_agentic=True,
        agent_metadata=AgentMetadata(
            provider=RegisteredAgentProvider.GCP,
            gcp_metadata=GCPAgentMetadata(
                project_id="test-project",
                region="test-region",
                resource_id="test-resource",
            ),
        ),
    )
    assert status_code == 200

    # Verify the response has agent_metadata (backward-compatible format)
    assert task_response.agent_metadata.provider == RegisteredAgentProvider.GCP.value
    assert task_response.agent_metadata.gcp_metadata.project_id == "test-project"
    assert task_response.agent_metadata.gcp_metadata.region == "test-region"
    assert task_response.agent_metadata.gcp_metadata.resource_id == "test-resource"

    # Verify task_metadata in DB has new creation_source format
    db_session = override_get_db_session()
    db_task = (
        db_session.query(DatabaseTask)
        .filter(DatabaseTask.id == task_response.id)
        .first()
    )
    assert db_task is not None
    assert db_task.task_metadata is not None
    creation_source = db_task.task_metadata.get("creation_source", {})
    assert creation_source.get("type") == "GCP"
    assert creation_source.get("gcp_project_id") == "test-project"
    assert creation_source.get("gcp_region") == "test-region"
    assert creation_source.get("gcp_reasoning_engine_id") == "test-resource"

    # Clean up
    status_code = client.delete_task(task_response.id)
    assert status_code == 204
