from __future__ import annotations
from typing import List, Dict
from .. import builder_constants as bc

"""Phase 2 (part 3): Kindred / tribal land additions (Land Step 3).

Extracted from `builder.py` to reduce monolith size. Focuses on lands that care
about creature types or tribal synergies when a selected tag includes 'Kindred' or 'Tribal'.

Provided by LandKindredMixin:
  - add_kindred_lands()
  - run_land_step3()

Host DeckBuilder must provide:
  - attributes: selected_tags, commander_tags, color_identity, ideal_counts, commander_row,
                card_library, _full_cards_df
  - methods: determine_color_identity(), setup_dataframes(), add_card(), _current_land_count(),
             _basic_floor(), _count_basic_lands(), _choose_basic_to_trim(), _decrement_card(),
             _enforce_land_cap(), output_func
"""

class LandKindredMixin:
    def add_kindred_lands(self):  # type: ignore[override]
        """Add kindred-oriented lands ONLY if a selected tag includes 'Kindred' or 'Tribal'.

        Baseline inclusions on kindred focus:
          - Path of Ancestry (always when kindred)
          - Cavern of Souls (<=4 colors)
          - Three Tree City (>=2 colors)
        Dynamic tribe-specific lands: derived only from selected tags (not all commander tags).
        Capacity: may swap excess basics (above 90% floor) similar to other steps.
        """
        if not getattr(self, 'files_to_load', []):
            try:
                self.determine_color_identity()
                self.setup_dataframes()
            except Exception as e:  # pragma: no cover - defensive
                self.output_func(f"Cannot add kindred lands until color identity resolved: {e}")
                return
        if not any(('kindred' in t.lower() or 'tribal' in t.lower()) for t in (getattr(self, 'selected_tags', []) or [])):
            self.output_func("Kindred Lands: No selected kindred/tribal tag; skipping.")
            return
        if hasattr(self, 'ideal_counts') and getattr(self, 'ideal_counts'):
            land_target = self.ideal_counts.get('lands', getattr(bc, 'DEFAULT_LAND_COUNT', 35))  # type: ignore[attr-defined]
        else:
            land_target = getattr(bc, 'DEFAULT_LAND_COUNT', 35)
        min_basic_cfg = getattr(bc, 'DEFAULT_BASIC_LAND_COUNT', 20)
        if hasattr(self, 'ideal_counts') and getattr(self, 'ideal_counts'):
            min_basic_cfg = self.ideal_counts.get('basic_lands', min_basic_cfg)  # type: ignore[attr-defined]
        basic_floor = self._basic_floor(min_basic_cfg)  # type: ignore[attr-defined]

        def ensure_capacity() -> bool:
            if self._current_land_count() < land_target:  # type: ignore[attr-defined]
                return True
            if self._count_basic_lands() <= basic_floor:  # type: ignore[attr-defined]
                return False
            target_basic = self._choose_basic_to_trim()  # type: ignore[attr-defined]
            if not target_basic:
                return False
            if not self._decrement_card(target_basic):  # type: ignore[attr-defined]
                return False
            return self._current_land_count() < land_target  # type: ignore[attr-defined]

        colors = getattr(self, 'color_identity', []) or []
        added: List[str] = []
        reasons: Dict[str, str] = {}

        def try_add(name: str, reason: str):
            if name in self.card_library:  # type: ignore[attr-defined]
                return
            if not ensure_capacity():
                return
            self.add_card(
                name,
                card_type='Land',
                role='kindred',
                sub_role='baseline' if reason.startswith('kindred focus') else 'tribe-specific',
                added_by='lands_step3',
                trigger_tag='Kindred/Tribal'
            )  # type: ignore[attr-defined]
            added.append(name)
            reasons[name] = reason

        # Baseline inclusions
        try_add('Path of Ancestry', 'kindred focus')
        if len(colors) <= 4:
            try_add('Cavern of Souls', f"kindred focus ({len(colors)} colors)")
        if len(colors) >= 2:
            try_add('Three Tree City', f"kindred focus ({len(colors)} colors)")

        # Dynamic tribe extraction
        tribe_terms: set[str] = set()
        for tag in (getattr(self, 'selected_tags', []) or []):
            lower = tag.lower()
            if 'kindred' in lower:
                base = lower.replace('kindred', '').strip()
                if base:
                    tribe_terms.add(base.split()[0])
            elif 'tribal' in lower:
                base = lower.replace('tribal', '').strip()
                if base:
                    tribe_terms.add(base.split()[0])

        snapshot = getattr(self, '_full_cards_df', None)
        if snapshot is not None and not snapshot.empty and tribe_terms:
            dynamic_limit = 5
            for tribe in sorted(tribe_terms):
                if self._current_land_count() >= land_target or dynamic_limit <= 0:  # type: ignore[attr-defined]
                    break
                tribe_lower = tribe.lower()
                matches: List[str] = []
                for _, row in snapshot.iterrows():
                    try:
                        nm = str(row.get('name', ''))
                        if not nm or nm in self.card_library:  # type: ignore[attr-defined]
                            continue
                        tline = str(row.get('type', row.get('type_line', ''))).lower()
                        if 'land' not in tline:
                            continue
                        text_field = row.get('text', row.get('oracleText', ''))
                        text_str = str(text_field).lower() if text_field is not None else ''
                        nm_lower = nm.lower()
                        if (tribe_lower in nm_lower or f" {tribe_lower}" in text_str or f"{tribe_lower} " in text_str or f"{tribe_lower}s" in text_str):
                            matches.append(nm)
                    except Exception:
                        continue
                for nm in matches[:2]:
                    if self._current_land_count() >= land_target or dynamic_limit <= 0:  # type: ignore[attr-defined]
                        break
                    if nm in added or nm in getattr(bc, 'BASIC_LANDS', []):
                        continue
                    try_add(nm, f"text/name references '{tribe}'")
                    dynamic_limit -= 1

        self.output_func("\nKindred Lands Added (Step 3):")
        if not added:
            self.output_func("  (None added)")
        else:
            width = max(len(n) for n in added)
            for n in added:
                self.output_func(f"  {n.ljust(width)} : 1  ({reasons.get(n,'')})")
        self.output_func(f"  Land Count Now : {self._current_land_count()} / {land_target}")  # type: ignore[attr-defined]

    def run_land_step3(self):  # type: ignore[override]
        """Public wrapper to add kindred-focused lands."""
        self.add_kindred_lands()
        self._enforce_land_cap(step_label="Kindred (Step 3)")  # type: ignore[attr-defined]
        try:
            from .. import builder_utils as _bu
            _bu.export_current_land_pool(self, '3')
        except Exception:
            pass


__all__ = [
    'LandKindredMixin'
]
