"""Tests for goal models and processor."""

import pytest
from xyglue.goal.models import Goal, GoalContext, GoalConstraint
from xyglue.goal.processor import GoalProcessor


class TestGoalContext:
    def test_default_context(self):
        ctx = GoalContext()
        assert ctx.domain == ""
        assert ctx.entities == []
        assert ctx.keywords == []
        assert ctx.complexity == "medium"
        assert ctx.priority == "normal"

    def test_to_dict(self):
        ctx = GoalContext(domain="web", keywords=["api", "rest"])
        d = ctx.to_dict()
        assert d["domain"] == "web"
        assert "api" in d["keywords"]

    def test_from_dict(self):
        data = {"domain": "data", "keywords": ["sql"], "complexity": "high"}
        ctx = GoalContext.from_dict(data)
        assert ctx.domain == "data"
        assert ctx.complexity == "high"


class TestGoalConstraint:
    def test_constraint_creation(self):
        c = GoalConstraint(name="budget", description="under $50", constraint_type="hard")
        assert c.name == "budget"
        assert c.constraint_type == "hard"

    def test_constraint_to_dict(self):
        c = GoalConstraint(name="tool", description="must use python", constraint_type="hard")
        d = c.to_dict()
        assert d["name"] == "tool"


class TestGoal:
    def test_basic_creation(self):
        g = Goal(raw="Build an API", normalized="Build an API")
        assert g.raw == "Build an API"

    def test_word_count(self):
        g = Goal(raw="Build a REST API server", normalized="Build a REST API server")
        assert g.word_count >= 4

    def test_to_dict(self):
        g = Goal(raw="test", normalized="Test")
        d = g.to_dict()
        assert d["raw"] == "test"
        assert "id" in d

    def test_from_dict(self):
        g = Goal(raw="test", normalized="Test")
        d = g.to_dict()
        g2 = Goal.from_dict(d)
        assert g2.raw == "test"
        assert g2.normalized == "Test"


class TestGoalProcessor:
    @pytest.fixture
    def processor(self):
        return GoalProcessor()

    async def test_basic_processing(self, processor):
        goal = await processor.process("build a rest api for user management")
        assert goal.normalized

    async def test_sanitization(self, processor):
        goal = await processor.process("<script>alert()</script> build an api")
        assert "<script>" not in goal.normalized

    async def test_normalization_capitalizes(self, processor):
        goal = await processor.process("build something")
        assert goal.normalized[0].isupper()

    async def test_domain_detection_web(self, processor):
        goal = await processor.process("Create a REST API endpoint with FastAPI")
        assert goal.goal_context.domain == "web"

    async def test_domain_detection_data(self, processor):
        goal = await processor.process("Query the PostgreSQL database for analytics")
        assert goal.goal_context.domain == "data"

    async def test_domain_detection_ml(self, processor):
        goal = await processor.process("Train a neural network model for classification")
        assert goal.goal_context.domain == "ml"

    async def test_keyword_extraction(self, processor):
        goal = await processor.process("Build a REST API server with authentication")
        assert len(goal.goal_context.keywords) > 0

    async def test_action_extraction(self, processor):
        goal = await processor.process("Build and deploy a web application")
        actions = goal.goal_context.actions
        assert "build" in actions or "deploy" in actions

    async def test_complexity_low(self, processor):
        goal = await processor.process("Simple hello world test")
        assert goal.goal_context.complexity == "low"

    async def test_complexity_high(self, processor):
        goal = await processor.process(
            "Build a distributed microservice architecture with real-time "
            "data pipeline and machine learning integration"
        )
        assert goal.goal_context.complexity == "high"

    async def test_priority_critical(self, processor):
        goal = await processor.process("Urgent: fix the production down issue immediately")
        assert goal.goal_context.priority == "critical"

    async def test_constraint_detection_budget(self, processor):
        goal = await processor.process("Build an API under $100 budget")
        assert len(goal.constraints) > 0
        assert any(c.name == "budget_limit" for c in goal.constraints)

    async def test_sub_goal_splitting_numbered(self, processor):
        goal = await processor.process("1. Fetch the data 2. Process it 3. Store results")
        assert len(goal.sub_goals) >= 2

    async def test_sub_goal_splitting_semicolons(self, processor):
        goal = await processor.process("Fetch data; process it; store results")
        assert len(goal.sub_goals) >= 2

    async def test_context_passthrough(self, processor):
        ctx = {"extra_key": "extra_value"}
        goal = await processor.process("Build something", context=ctx)
        assert goal.context.get("extra_key") == "extra_value"
