"""Tests for the MQL parser, planner, and executor."""

import pytest

from locidb.query.parser import (
    MQLParseError,
    MemorizeCommand,
    RecallQuery,
    parse,
)
from locidb.query.planner import MemorizePlan, RecallPlan, plan


# ── Parser ─────────────────────────────────────────────────────────────

class TestParser:
    def test_basic_recall(self):
        mql = 'RECALL content, importance FROM memory WHERE SIMILAR_TO("delivery optimization") LIMIT 5;'
        result = parse(mql)
        assert isinstance(result, RecallQuery)
        assert result.similar_to == "delivery optimization"
        assert result.limit == 5
        assert "content" in result.fields
        assert "importance" in [f.strip() for f in result.fields]

    def test_recall_with_all_clauses(self):
        mql = '''
        RECALL * FROM memory
        WHERE SIMILAR_TO("delivery optimization", threshold=0.75)
        AND importance > 0.7
        AND ENTITY_MATCH(["Dropzi", "routing"])
        AND timestamp WITHIN LAST 30 DAYS
        LIMIT 10;
        '''
        result = parse(mql)
        assert isinstance(result, RecallQuery)
        assert result.similar_to == "delivery optimization"
        assert result.similarity_threshold == 0.75
        assert result.min_importance == 0.7
        assert "Dropzi" in result.entity_match
        assert "routing" in result.entity_match
        assert result.time_window_days == 30
        assert result.limit == 10

    def test_recall_with_scope(self):
        mql = 'RECALL * FROM memory WHERE scope = "project:dropzi" LIMIT 5;'
        result = parse(mql)
        assert isinstance(result, RecallQuery)
        assert result.scope == "project:dropzi"

    def test_memorize_basic(self):
        mql = '''
        MEMORIZE {
            content: "Decided to use hub-spoke model",
            entities: ["Dropzi", "architecture"],
            scope: "project:dropzi"
        } WITH AUTO_SCORE;
        '''
        result = parse(mql)
        assert isinstance(result, MemorizeCommand)
        assert "hub-spoke" in result.content
        assert "Dropzi" in result.entities
        assert result.scope == "project:dropzi"
        assert result.auto_score is True

    def test_memorize_without_auto_score(self):
        mql = 'MEMORIZE { content: "hello", entities: [] }'
        result = parse(mql)
        assert isinstance(result, MemorizeCommand)
        assert result.auto_score is False

    def test_invalid_statement(self):
        with pytest.raises(MQLParseError):
            parse("SELECT * FROM memory")


# ── Planner ────────────────────────────────────────────────────────────

class TestPlanner:
    def test_recall_plan(self):
        ast = RecallQuery(
            similar_to="test query",
            min_importance=0.5,
            entity_match=["A"],
            limit=3,
        )
        p = plan(ast)
        assert isinstance(p, RecallPlan)
        assert p.query_text == "test query"
        assert p.min_importance == 0.5
        assert p.entity_filter == ["A"]
        assert p.limit == 3

    def test_memorize_plan(self):
        ast = MemorizeCommand(
            content="test content",
            entities=["X"],
            scope="project:test",
            auto_score=True,
        )
        p = plan(ast)
        assert isinstance(p, MemorizePlan)
        assert p.content == "test content"
        assert p.entities == ["X"]
        assert p.scope == "project:test"
