"""Tests for questionnaire definitions and computed defaults."""

from __future__ import annotations

from exokit.core.models import QuestionnaireAnswers, ScaffoldContext
from exokit.core.questionnaire import (
    DEFAULT_COMPUTERS,
    QUESTIONS,
    build_context,
    compute_default,
)


class TestQuestionDefinitions:
    """Tests that QUESTIONS list is well-formed."""

    def test_questions_not_empty(self) -> None:
        assert len(QUESTIONS) >= 7

    def test_all_questions_have_unique_ids(self) -> None:
        ids = [q.id for q in QUESTIONS]
        assert len(ids) == len(set(ids)), "Duplicate question IDs found"

    def test_required_questions_present(self) -> None:
        ids = {q.id for q in QUESTIONS}
        required = {
            "company",
            "industry",
            "catalog",
            "warehouse_id",
            "workspace_host",
            "notification_email",
        }
        assert required.issubset(ids)

    def test_optional_questions_present(self) -> None:
        ids = {q.id for q in QUESTIONS}
        optional = {"databricks_profile", "lakebase_url"}
        assert optional.issubset(ids)

    def test_industry_has_options(self) -> None:
        industry_q = next(q for q in QUESTIONS if q.id == "industry")
        assert industry_q.type == "select"
        assert industry_q.options is not None
        assert len(industry_q.options) >= 5
        assert "fsi" in industry_q.options
        assert "telecom" in industry_q.options

    def test_select_questions_have_options(self) -> None:
        for q in QUESTIONS:
            if q.type == "select":
                assert q.options is not None and len(q.options) > 0, (
                    f"Select question '{q.id}' must have options"
                )

    def test_text_questions_no_options(self) -> None:
        for q in QUESTIONS:
            if q.type == "text":
                assert q.options is None, f"Text question '{q.id}' should not have options"

    def test_catalog_has_default_from(self) -> None:
        catalog_q = next(q for q in QUESTIONS if q.id == "catalog")
        assert catalog_q.default_from is not None
        assert catalog_q.default_from in DEFAULT_COMPUTERS

    def test_all_default_from_keys_registered(self) -> None:
        """Every default_from reference must exist in DEFAULT_COMPUTERS."""
        for q in QUESTIONS:
            if q.default_from is not None:
                assert q.default_from in DEFAULT_COMPUTERS, (
                    f"Question '{q.id}' references unregistered compute function '{q.default_from}'"
                )

    def test_questions_json_serializable(self) -> None:
        """All questions must be JSON-serializable for V2 web forms."""
        for q in QUESTIONS:
            json_str = q.model_dump_json()
            assert len(json_str) > 0


class TestComputeDefault:
    """Tests for compute_default function."""

    def test_catalog_computed_from_company_industry(self) -> None:
        catalog_q = next(q for q in QUESTIONS if q.id == "catalog")
        answers = {"company": "Acme Bank", "industry": "fsi"}
        result = compute_default(catalog_q, answers)
        assert result == "acme_bank_fsi"

    def test_catalog_computed_handles_spaces(self) -> None:
        catalog_q = next(q for q in QUESTIONS if q.id == "catalog")
        answers = {"company": "Big Corp Inc", "industry": "telecom"}
        result = compute_default(catalog_q, answers)
        assert result == "big_corp_inc_telecom"

    def test_static_default_returned(self) -> None:
        profile_q = next(q for q in QUESTIONS if q.id == "databricks_profile")
        result = compute_default(profile_q, {})
        assert result == "DEFAULT"

    def test_no_default_returns_none(self) -> None:
        company_q = next(q for q in QUESTIONS if q.id == "company")
        result = compute_default(company_q, {})
        assert result is None


class TestBuildContext:
    """Tests for build_context factory function."""

    def test_build_context_computes_bundle_name(self, sample_answers: QuestionnaireAnswers) -> None:
        ctx = build_context(sample_answers)
        assert ctx.bundle_name == "acme-bank-fsi-demo"

    def test_build_context_computes_app_name(self, sample_answers: QuestionnaireAnswers) -> None:
        ctx = build_context(sample_answers)
        assert ctx.app_name == "acme-bank-fsi-app"

    def test_build_context_preserves_answers(self, sample_answers: QuestionnaireAnswers) -> None:
        ctx = build_context(sample_answers)
        assert ctx.company == sample_answers.company
        assert ctx.industry == sample_answers.industry
        assert ctx.catalog == sample_answers.catalog
        assert ctx.warehouse_id == sample_answers.warehouse_id
        assert ctx.workspace_host == sample_answers.workspace_host
        assert ctx.notification_email == sample_answers.notification_email

    def test_build_context_returns_scaffold_context(
        self, sample_answers: QuestionnaireAnswers
    ) -> None:
        ctx = build_context(sample_answers)
        assert isinstance(ctx, ScaffoldContext)

    def test_build_context_handles_spaces_in_company(self) -> None:
        answers = QuestionnaireAnswers(
            company="My Big Company",
            industry="retail",
            demo_description="Test demo description",
            catalog="my_big_company_retail",
            warehouse_id="wh123",
            workspace_host="https://test.databricks.net",
            notification_email="test@test.com",
        )
        ctx = build_context(answers)
        assert ctx.bundle_name == "my-big-company-retail-demo"
        assert ctx.app_name == "my-big-company-retail-app"

    def test_build_context_lowercase(self) -> None:
        answers = QuestionnaireAnswers(
            company="ACME",
            industry="FSI",
            demo_description="Test",
            catalog="acme_fsi",
            warehouse_id="wh123",
            workspace_host="https://test.databricks.net",
            notification_email="test@test.com",
        )
        ctx = build_context(answers)
        assert ctx.bundle_name == "acme-fsi-demo"
        assert ctx.app_name == "acme-fsi-app"
