"""Unit-Tests fuer den Founding-Wizard Service.

Testet:
- Template-Renderer mit verschiedenen Inputs
- Wizard-State -> Context Mapping
- Markdown -> DOCX Konvertierung
"""

from __future__ import annotations

import pytest

from compliance.services.founding_wizard.template_renderer import (
    find_undefined_placeholders,
    render_template,
)
from compliance.services.founding_wizard.wizard_to_context import base_context


class TestTemplateRenderer:
    def test_simple_variable_substitution(self):
        result = render_template("Hallo {{NAME}}!", {"NAME": "Welt"})
        assert result == "Hallo Welt!"

    def test_missing_variable_placeholder(self):
        result = render_template("Hallo {{NAME}}!", {})
        assert "[NAME fehlt]" in result

    def test_if_block_truthy(self):
        result = render_template(
            "Start {{#IF FLAG}}drin{{/IF}} Ende",
            {"FLAG": True}
        )
        assert result == "Start drin Ende"

    def test_if_block_falsy(self):
        result = render_template(
            "Start {{#IF FLAG}}drin{{/IF}} Ende",
            {"FLAG": False}
        )
        assert result == "Start  Ende"

    def test_if_not_block(self):
        result = render_template(
            "{{#IF NOT FLAG}}negiert{{/IF}}",
            {"FLAG": False}
        )
        assert "negiert" in result

    def test_truthy_int(self):
        result = render_template("{{#IF N}}yes{{/IF}}", {"N": 5})
        assert "yes" in result

    def test_falsy_zero(self):
        result = render_template("{{#IF N}}yes{{/IF}}", {"N": 0})
        assert "yes" not in result

    def test_truthy_list(self):
        result = render_template("{{#IF L}}yes{{/IF}}", {"L": [1, 2]})
        assert "yes" in result

    def test_falsy_empty_list(self):
        result = render_template("{{#IF L}}yes{{/IF}}", {"L": []})
        assert "yes" not in result

    def test_nested_if_blocks(self):
        template = "{{#IF A}}A-on{{#IF B}}+B-on{{/IF}}{{/IF}}"
        result = render_template(template, {"A": True, "B": True})
        assert result == "A-on+B-on"

    def test_nested_outer_false_inner_true(self):
        """Bug-Regression: nested IF in outer-false darf nicht den falschen close-tag matchen."""
        template = "{{#IF OUTER}}outer-{{#IF INNER}}inner{{/IF}}-end{{/IF}}AFTER"
        result = render_template(template, {"OUTER": False, "INNER": True})
        assert result == "AFTER"
        assert "{{/IF}}" not in result
        assert "outer" not in result

    def test_consecutive_if_blocks(self):
        """Bug-Regression: 2 aufeinanderfolgende IF-Bloecke."""
        template = "{{#IF A}}a{{/IF}}{{#IF B}}b{{/IF}}"
        result = render_template(template, {"A": False, "B": True})
        assert result == "b"
        assert "{{" not in result

    def test_orphan_if_tag_removed(self):
        """Orphan {{/IF}} aufraeumen."""
        template = "Text{{/IF}}mehr"
        result = render_template(template, {})
        assert "{{/IF}}" not in result

    def test_real_go_gf_pattern(self):
        """Realistic Pattern aus GO-GF Template."""
        template = (
            "{{#IF HAS_CEO_DESIGNATION}}Mit CEO {{CEO_NAME}}{{#IF HAS_SHA}} und SHA{{/IF}}.{{/IF}}"
            "{{#IF NOT HAS_CEO_DESIGNATION}}Kein CEO. Eskalation nach § 6.{{/IF}}"
        )
        # Fall: kein CEO, kein SHA
        r1 = render_template(template, {"HAS_CEO_DESIGNATION": False, "HAS_SHA": False})
        assert r1 == "Kein CEO. Eskalation nach § 6."
        # Fall: CEO + SHA
        r2 = render_template(template, {"HAS_CEO_DESIGNATION": True, "HAS_SHA": True, "CEO_NAME": "Benjamin"})
        assert r2 == "Mit CEO Benjamin und SHA."
        # Fall: CEO ohne SHA
        r3 = render_template(template, {"HAS_CEO_DESIGNATION": True, "HAS_SHA": False, "CEO_NAME": "Benjamin"})
        assert r3 == "Mit CEO Benjamin."

    def test_find_undefined_placeholders(self):
        template = "{{X}} {{Y}} {{#IF Z}}.{{/IF}}"
        undefined = find_undefined_placeholders(template, {"X": "1"})
        assert "Y" in undefined
        assert "Z" in undefined
        assert "X" not in undefined


class TestWizardToContext:
    def _basic_state(self) -> dict:
        return {
            "basics": {
                "company_name": "Test GmbH",
                "legal_form": "GmbH",
                "company_seat": "Stuttgart",
                "company_address": "Königstraße 1, 70173 Stuttgart",
                "company_purpose_description": "Test purpose",
                "company_purpose_bullets": ["a) Test", "b) Test 2"],
                "industry": "SaaS",
                "business_year": "Kalenderjahr",
                "has_research_focus": True,
            },
            "capital": {
                "stammkapital_eur": 25000,
                "einlage_method": "Geld",
                "einlage_quote_initial_pct": 50,
                "has_sacheinlage": False,
            },
            "gesellschafter": [
                {
                    "id": "g1", "anteil_nr": 1, "name": "Benjamin Bönisch",
                    "geburtsdatum": "1980-01-01", "adresse": "Test 1",
                    "nennbetrag_eur": 12500, "is_geschaeftsfuehrer": True,
                    "internal_role": "CEO", "rolle": "founder",
                    "has_academic_background": False,
                },
                {
                    "id": "g2", "anteil_nr": 2, "name": "Sharang Parnerkar",
                    "geburtsdatum": "1985-05-15", "adresse": "Test 2",
                    "nennbetrag_eur": 12500, "is_geschaeftsfuehrer": True,
                    "internal_role": "CTO", "rolle": "founder",
                    "has_academic_background": False,
                },
            ],
            "notar": {
                "notary_name": "Dr. Notar",
                "notary_place": "Stuttgart",
                "notarial_date": "2026-06-01",
            },
            "sha": {
                "has_sha": True,
                "vesting_months": 48,
                "cliff_months": 12,
                "drag_along_threshold_pct": 75,
                "tag_along_threshold_pct": 20,
                "reserved_matters_majority_pct": 75,
                "has_beirat": False,
                "has_texas_shootout": False,
                "has_ceo_designation": False,
            },
        }

    def test_basics_in_context(self):
        ctx = base_context(self._basic_state())
        assert ctx["COMPANY_NAME"] == "Test GmbH"
        assert ctx["COMPANY_LEGAL_FORM"] == "GmbH"
        assert ctx["COMPANY_SEAT"] == "Stuttgart"
        assert ctx["STAMMKAPITAL_EUR"] == "25.000"

    def test_num_gf_2_man(self):
        ctx = base_context(self._basic_state())
        assert ctx["NUM_GF"] == 2
        assert ctx["NUM_GF_TEXT"] == "zwei"
        assert ctx["IS_MULTI_GF"] is True
        assert ctx["NUM_GF_IS_2"] is True
        assert ctx["NUM_GF_GT_2"] is False

    def test_parties_list_format(self):
        ctx = base_context(self._basic_state())
        plist = ctx["PARTIES_LIST"]
        assert "Benjamin Bönisch" in plist
        assert "Sharang Parnerkar" in plist
        assert "a)" in plist
        assert "b)" in plist

    def test_flags_default(self):
        ctx = base_context(self._basic_state())
        assert ctx["HAS_SHA"] is True
        assert ctx["HAS_RESEARCH_FOCUS"] is True
        assert ctx["HAS_ACADEMIC_FOUNDER"] is False
        assert ctx["HAS_BEIRAT"] is False

    def test_academic_flag_detection(self):
        state = self._basic_state()
        state["gesellschafter"][0]["has_academic_background"] = True
        ctx = base_context(state)
        assert ctx["HAS_ACADEMIC_FOUNDER"] is True


class TestMarkdownToDocx:
    def test_basic_conversion(self):
        from compliance.services.founding_wizard.markdown_to_docx import markdown_to_docx_bytes
        md = "# Titel\n\nDas ist ein Absatz.\n\n## Unterthema\n\n- Punkt 1\n- Punkt 2"
        result = markdown_to_docx_bytes(md)
        assert isinstance(result, bytes)
        # DOCX is a ZIP file starting with PK\x03\x04
        assert result[:4] == b"PK\x03\x04"
        assert len(result) > 1000  # reasonable size

    def test_table_conversion(self):
        from compliance.services.founding_wizard.markdown_to_docx import markdown_to_docx_bytes
        md = "| A | B |\n| --- | --- |\n| 1 | 2 |\n| 3 | 4 |"
        result = markdown_to_docx_bytes(md)
        assert result[:4] == b"PK\x03\x04"

    def test_bold_italic(self):
        from compliance.services.founding_wizard.markdown_to_docx import markdown_to_docx_bytes
        md = "Das ist **fett** und _kursiv_ und `code`."
        result = markdown_to_docx_bytes(md)
        assert result[:4] == b"PK\x03\x04"


class TestPerPersonContext:
    """Tests fuer per-person Context-Building (IP-Assignment, GF-Vertrag)."""

    def test_build_person_context_ip_areas_as_list(self):
        from compliance.api.founding_wizard_routes import _build_person_context
        base = {"COMPANY_NAME": "X GmbH"}
        person = {
            "name": "Benjamin Bönisch",
            "geburtsdatum": "1980-01-01",
            "adresse": "Test 1",
            "internal_role": "CEO",
            "ip_areas": ["Compliance-Engine", "RAG-Pipeline"],
        }
        ctx = _build_person_context(base, person, "ip_assignment_agreement")
        assert ctx["ASSIGNOR_NAME"] == "Benjamin Bönisch"
        assert "Compliance-Engine" in ctx["IP_LIST_DETAILS"]
        assert "RAG-Pipeline" in ctx["IP_LIST_DETAILS"]
        # Two distinct persons should yield distinct IP_LIST_DETAILS
        person2 = {**person, "name": "Sharang", "ip_areas": ["Security", "Infrastruktur"]}
        ctx2 = _build_person_context(base, person2, "ip_assignment_agreement")
        assert ctx["IP_LIST_DETAILS"] != ctx2["IP_LIST_DETAILS"]
        assert "Security" in ctx2["IP_LIST_DETAILS"]

    def test_build_person_context_fallback_when_no_ip_areas(self):
        """Wenn keine ip_areas gesetzt sind, behaelt der Context den Default aus base."""
        from compliance.api.founding_wizard_routes import _build_person_context
        base = {"COMPANY_NAME": "X GmbH", "IP_LIST_DETAILS": "- Default IP"}
        person = {"name": "Foo", "ip_areas": []}
        ctx = _build_person_context(base, person, "ip_assignment_agreement")
        assert ctx["IP_LIST_DETAILS"] == "- Default IP"

    def test_safe_slug_handles_special_chars(self):
        from compliance.api.founding_wizard_routes import _safe_slug
        assert _safe_slug("Benjamin Bönisch") == "Benjamin_B_nisch"
        assert _safe_slug("Sharang Parnerkar") == "Sharang_Parnerkar"
        assert _safe_slug("") == "Person"
        assert _safe_slug("   ") == "Person"

    def test_per_person_docs_set_contains_expected(self):
        from compliance.api.founding_wizard_routes import PER_PERSON_DOCS
        assert "ip_assignment_agreement" in PER_PERSON_DOCS
        assert "managing_director_employment_contract" in PER_PERSON_DOCS
        # Satzung etc. duerfen NICHT per-person sein:
        assert "articles_of_association" not in PER_PERSON_DOCS
        assert "sha" not in PER_PERSON_DOCS


class TestBasicsRegisterCourt:
    def test_register_court_propagates(self):
        state = TestWizardToContext()._basic_state()
        state["basics"]["register_court"] = "Amtsgericht Stuttgart"
        state["basics"]["hrb_number"] = "HRB 12345"
        ctx = base_context(state)
        assert ctx["REGISTER_COURT"] == "Amtsgericht Stuttgart"
        assert ctx["COMPANY_REGISTRY_COURT"] == "Amtsgericht Stuttgart"
        assert ctx["HRB_NUMBER"] == "HRB 12345"
        assert ctx["HAS_HRB"] is True

    def test_register_court_default_when_missing(self):
        ctx = base_context(TestWizardToContext()._basic_state())
        assert "[zuständiges Amtsgericht]" in ctx["REGISTER_COURT"]
        assert ctx["HAS_HRB"] is False


class TestEndToEndRendering:
    """Test mit echtem Template-aehnlichen Markdown + 2-Mann GmbH Daten."""

    def test_minimum_satzung_render(self):
        template = """# Satzung der {{COMPANY_NAME}}

## § 1 Firma
(1) Die Gesellschaft führt die Firma {{COMPANY_NAME}}.
(2) Sitz ist {{COMPANY_SEAT}}.

{{#IF HAS_SHA}}
## § 5 SHA-Verweis
Es gilt das SHA.
{{/IF}}

{{#IF NOT HAS_SHA}}
## § 5 Hinweis
Kein SHA vereinbart.
{{/IF}}
"""
        ctx = base_context(TestWizardToContext()._basic_state())
        result = render_template(template, ctx)

        assert "Test GmbH" in result
        assert "Stuttgart" in result
        assert "§ 5 SHA-Verweis" in result
        assert "Kein SHA vereinbart" not in result
