"""Tests for InterviewState and InterviewStateManager."""

import pytest
import json
import tempfile
from pathlib import Path
from datetime import datetime

from optimization_engine.interview.interview_state import (
    InterviewState,
    InterviewPhase,
    InterviewStateManager,
    AnsweredQuestion,
    LogEntry,
)


class TestInterviewPhase:
    """Tests for InterviewPhase enum."""

    def test_from_string(self):
        """Test converting string to enum."""
        assert InterviewPhase.from_string("introspection") == InterviewPhase.INTROSPECTION
        assert InterviewPhase.from_string("objectives") == InterviewPhase.OBJECTIVES
        assert InterviewPhase.from_string("complete") == InterviewPhase.COMPLETE

    def test_from_string_invalid(self):
        """Test invalid string raises error."""
        with pytest.raises(ValueError):
            InterviewPhase.from_string("invalid_phase")

    def test_next_phase(self):
        """Test getting next phase."""
        assert InterviewPhase.INTROSPECTION.next_phase() == InterviewPhase.PROBLEM_DEFINITION
        assert InterviewPhase.OBJECTIVES.next_phase() == InterviewPhase.CONSTRAINTS
        assert InterviewPhase.COMPLETE.next_phase() is None

    def test_previous_phase(self):
        """Test getting previous phase."""
        assert InterviewPhase.OBJECTIVES.previous_phase() == InterviewPhase.PROBLEM_DEFINITION
        assert InterviewPhase.INTROSPECTION.previous_phase() is None


class TestAnsweredQuestion:
    """Tests for AnsweredQuestion dataclass."""

    def test_to_dict(self):
        """Test conversion to dict."""
        aq = AnsweredQuestion(
            question_id="obj_01",
            answered_at="2026-01-02T10:00:00",
            raw_response="minimize mass",
            parsed_value="minimize_mass",
            inferred={"extractor": "E4"}
        )

        d = aq.to_dict()
        assert d["question_id"] == "obj_01"
        assert d["parsed_value"] == "minimize_mass"
        assert d["inferred"]["extractor"] == "E4"

    def test_from_dict(self):
        """Test creation from dict."""
        data = {
            "question_id": "obj_01",
            "answered_at": "2026-01-02T10:00:00",
            "raw_response": "minimize mass",
            "parsed_value": "minimize_mass",
        }

        aq = AnsweredQuestion.from_dict(data)
        assert aq.question_id == "obj_01"
        assert aq.parsed_value == "minimize_mass"


class TestInterviewState:
    """Tests for InterviewState dataclass."""

    def test_default_values(self):
        """Test default initialization."""
        state = InterviewState()
        assert state.version == "1.0"
        assert state.session_id != ""
        assert state.current_phase == InterviewPhase.INTROSPECTION.value
        assert state.complexity == "simple"
        assert state.answers["objectives"] == []

    def test_get_phase(self):
        """Test getting phase as enum."""
        state = InterviewState(current_phase="objectives")
        assert state.get_phase() == InterviewPhase.OBJECTIVES

    def test_set_phase(self):
        """Test setting phase."""
        state = InterviewState()
        state.set_phase(InterviewPhase.CONSTRAINTS)
        assert state.current_phase == "constraints"

    def test_is_complete(self):
        """Test completion check."""
        state = InterviewState(current_phase="review")
        assert not state.is_complete()

        state.current_phase = "complete"
        assert state.is_complete()

    def test_progress_percentage(self):
        """Test progress calculation."""
        state = InterviewState(current_phase="introspection")
        assert state.progress_percentage() == 0.0

        state.current_phase = "complete"
        assert state.progress_percentage() == 100.0

    def test_add_answered_question(self):
        """Test adding answered question."""
        state = InterviewState()
        aq = AnsweredQuestion(
            question_id="pd_01",
            answered_at=datetime.now().isoformat(),
            raw_response="test",
            parsed_value="test"
        )

        state.add_answered_question(aq)
        assert len(state.questions_answered) == 1

    def test_add_warning(self):
        """Test adding warnings."""
        state = InterviewState()
        state.add_warning("Test warning")
        assert "Test warning" in state.warnings

        # Duplicate should not be added
        state.add_warning("Test warning")
        assert len(state.warnings) == 1

    def test_acknowledge_warning(self):
        """Test acknowledging warnings."""
        state = InterviewState()
        state.add_warning("Test warning")
        state.acknowledge_warning("Test warning")
        assert "Test warning" in state.warnings_acknowledged

    def test_to_json(self):
        """Test JSON serialization."""
        state = InterviewState(study_name="test_study")
        json_str = state.to_json()

        data = json.loads(json_str)
        assert data["study_name"] == "test_study"
        assert data["version"] == "1.0"

    def test_from_json(self):
        """Test JSON deserialization."""
        json_str = '{"version": "1.0", "session_id": "abc", "study_name": "test", "current_phase": "objectives", "answers": {}}'
        state = InterviewState.from_json(json_str)

        assert state.study_name == "test"
        assert state.current_phase == "objectives"

    def test_validate(self):
        """Test state validation."""
        state = InterviewState()
        errors = state.validate()
        assert "Missing study_name" in errors

        state.study_name = "test"
        errors = state.validate()
        assert "Missing study_name" not in errors


class TestInterviewStateManager:
    """Tests for InterviewStateManager."""

    def test_init_creates_directories(self):
        """Test initialization creates needed directories."""
        with tempfile.TemporaryDirectory() as tmpdir:
            study_path = Path(tmpdir) / "test_study"
            study_path.mkdir()

            manager = InterviewStateManager(study_path)

            assert (study_path / ".interview").exists()
            assert (study_path / ".interview" / "backups").exists()

    def test_save_and_load_state(self):
        """Test saving and loading state."""
        with tempfile.TemporaryDirectory() as tmpdir:
            study_path = Path(tmpdir) / "test_study"
            study_path.mkdir()

            manager = InterviewStateManager(study_path)

            state = InterviewState(
                study_name="test_study",
                study_path=str(study_path),
                current_phase="objectives"
            )

            manager.save_state(state)
            assert manager.exists()

            loaded = manager.load_state()
            assert loaded is not None
            assert loaded.study_name == "test_study"
            assert loaded.current_phase == "objectives"

    def test_append_log(self):
        """Test appending to log file."""
        with tempfile.TemporaryDirectory() as tmpdir:
            study_path = Path(tmpdir) / "test_study"
            study_path.mkdir()

            manager = InterviewStateManager(study_path)

            entry = LogEntry(
                timestamp=datetime.now(),
                question_id="obj_01",
                question_text="What is your goal?",
                answer_raw="minimize mass",
                answer_parsed="minimize_mass"
            )

            manager.append_log(entry)

            assert manager.log_file.exists()
            content = manager.log_file.read_text()
            assert "obj_01" in content
            assert "minimize mass" in content

    def test_backup_rotation(self):
        """Test backup rotation keeps only N backups."""
        with tempfile.TemporaryDirectory() as tmpdir:
            study_path = Path(tmpdir) / "test_study"
            study_path.mkdir()

            manager = InterviewStateManager(study_path)
            manager.MAX_BACKUPS = 3

            # Create multiple saves
            for i in range(5):
                state = InterviewState(
                    study_name=f"test_{i}",
                    study_path=str(study_path)
                )
                manager.save_state(state)

            backups = list(manager.backup_dir.glob("state_*.json"))
            assert len(backups) <= 3

    def test_get_history(self):
        """Test getting modification history."""
        with tempfile.TemporaryDirectory() as tmpdir:
            study_path = Path(tmpdir) / "test_study"
            study_path.mkdir()

            manager = InterviewStateManager(study_path)

            # Save multiple states
            for i in range(3):
                state = InterviewState(
                    study_name=f"test_{i}",
                    study_path=str(study_path),
                    current_phase=["objectives", "constraints", "review"][i]
                )
                manager.save_state(state)

            history = manager.get_history()
            # Should have 2 backups (first save doesn't create backup)
            assert len(history) >= 1


class TestLogEntry:
    """Tests for LogEntry dataclass."""

    def test_to_markdown(self):
        """Test markdown generation."""
        entry = LogEntry(
            timestamp=datetime(2026, 1, 2, 10, 30, 0),
            question_id="obj_01",
            question_text="What is your primary optimization goal?",
            answer_raw="minimize mass",
            answer_parsed="minimize_mass",
            inferred={"extractor": "E4"},
            warnings=["Consider safety factor"]
        )

        md = entry.to_markdown()

        assert "## [2026-01-02 10:30:00]" in md
        assert "obj_01" in md
        assert "minimize mass" in md
        assert "Extractor" in md.lower() or "extractor" in md
        assert "Consider safety factor" in md
