# tests/stubs/single_choice_question.py
import pytest
from datetime import datetime
from dataclasses import dataclass, field
from typing import List
from flexoentity import FlexOID, FlexoEntity, EntityType, EntityState, Domain

@pytest.fixture
def fixed_datetime(monkeypatch):
    class FixedDate(datetime):
        @classmethod
        def now(cls, tz=None):
            return datetime(2025, 11, 1, tzinfo=tz)
    monkeypatch.setattr("flexoentity.id_factory.datetime", FixedDate)
    return FixedDate


@dataclass
class AnswerOption:
    id: str
    text: str
    points: float = 0.0

    def to_dict(self):
        return {"id": self.id, "text": self.text, "points": self.points}

    @classmethod
    def from_dict(cls, data):
        return cls(
            id=data.get("id", ""),
            text=data.get("text", ""),
            points=data.get("points", 0.0)
        )


@dataclass
class SingleChoiceQuestion(FlexoEntity):
    """A minimal stub to test FlexoEntity integration."""
    ENTITY_TYPE = EntityType.ITEM

    text: str = ""
    options: List[AnswerOption] = field(default_factory=list)

    def __post_init__(self):
        # If no FlexOID yet, generate a draft ID now.
        if not getattr(self, "flexo_id", None):
            self.flexo_id = FlexOID.safe_generate(
                domain=self.domain_id,
                entity_type=SingleChoiceQuestion.ENTITY_TYPE.value,     # 'I'
                estate=EntityState.DRAFT.value,        # 'D'
                text=self.text_seed or self.text,
                version=1,
            )

    @classmethod
    def default(cls):
        return cls()

    def to_dict(self):
        base = super().to_dict()
        base.update({
            "text": self.text,
            "options": [opt.to_dict() for opt in self.options],
        })
        return base

    @property
    def text_seed(self) -> str:
        """Include answer options (and points) for deterministic ID generation."""

        joined = "|".join(
            f"{opt.text.strip()}:{opt.points}"
            for opt in sorted(self.options, key=lambda o: o.text.strip().lower())
        )
        return f"{self.text}{joined}"

    @classmethod
    def from_dict(cls, data):
        obj = cls(text=data.get("text", ""),
            options=[AnswerOption.from_dict(o) for o in data.get("options", [])],
        )
        # restore FlexoEntity core fields
        if "flexo_id" in data:
            obj.flexo_id = FlexOID.parsed(data["flexo_id"])
        return obj

@pytest.fixture
def sample_domain():
    domain_id = "PY_ARITHM"
    flexo_id = FlexOID.safe_generate(domain_id=domain_id,
                                     entity_type=EntityType.DOMAIN.value,
                                     state=EntityState.DRAFT.value, text=domain_id)
    return Domain(flexo_id=flexo_id, fullname="PYTHON_ARITHMETIC",
                  description="ALL ABOUT ARITHMETIC IN PYTHON")

@pytest.fixture
def sample_question(sample_domain):
    flexo_id = FlexOID.safe_generate(domain_id=sample_domain.domain_id,
                                     entity_type=EntityType.ITEM.value,
                                     state=EntityState.DRAFT.value,
                                     text="What is 2 + 2")
    q = SingleChoiceQuestion(flexo_id=flexo_id, text="What is 2 + 2?",
                             options=[])
    q._update_fingerprint()
    return q
