from __future__ import annotations
from typing import Dict, Optional
from .. import builder_constants as bc
import os

"""Phase 2 (part 1): Basic land addition logic (Land Step 1).

Extracted from the monolithic `builder.py` to begin modularizing land building.

Responsibilities provided by this mixin:
  - add_basic_lands(): core allocation & addition of basic (or snow) lands.
  - run_land_step1(): public wrapper invoked by the deck build orchestrator.

Expected attributes / methods on the host DeckBuilder:
  - color_identity, selected_tags, commander_tags, ideal_counts
  - determine_color_identity(), setup_dataframes(), add_card()
  - output_func for user messaging
  - bc (builder_constants) imported in builder module; we import locally here.
"""

 # (Imports moved to top for lint compliance)


class LandBasicsMixin:
    def add_basic_lands(self):  # type: ignore[override]
        """Add basic (or snow basic) lands based on color identity.

        Logic:
          - Determine target basics = ceil(1.3 * ideal_basic_min) (rounded) but capped by total land target
          - Evenly distribute among colored identity letters (W,U,B,R,G)
          - If commander/selected tags include 'Snow' (case-insensitive) use snow basics mapping
          - Colorless commander: use Wastes for the entire basic allocation
        """
        # Ensure color identity determined
        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 basics until color identity resolved: {e}")
                return

        # DEBUG EXPORT: write full land pool snapshot the first time basics are added
        # Purpose: allow inspection of all candidate land cards before other land steps mutate state.
        try:  # pragma: no cover (diagnostic aid)
            full_df = getattr(self, '_combined_cards_df', None)
            marker_attr = '_land_debug_export_done'
            if full_df is not None and not getattr(self, marker_attr, False):
                land_df = full_df
                # Prefer 'type' column (common) else attempt 'type_line'
                col = 'type' if 'type' in land_df.columns else ('type_line' if 'type_line' in land_df.columns else None)
                if col:
                    work = land_df[land_df[col].fillna('').str.contains('Land', case=False, na=False)].copy()
                    if not work.empty:
                        os.makedirs(os.path.join('logs', 'debug'), exist_ok=True)
                        export_cols = [c for c in ['name','type','type_line','manaValue','edhrecRank','colorIdentity','manaCost','themeTags','oracleText'] if c in work.columns]
                        path = os.path.join('logs','debug','land_test.csv')
                        try:
                            if export_cols:
                                work[export_cols].to_csv(path, index=False, encoding='utf-8')
                            else:
                                work.to_csv(path, index=False, encoding='utf-8')
                        except Exception:
                            work.to_csv(path, index=False)
                        self.output_func(f"[DEBUG] Wrote land_test.csv ({len(work)} rows)")
                        setattr(self, marker_attr, True)
        except Exception:
            pass

        # Ensure ideal counts (for min basics & total lands)
        basic_min: Optional[int] = None
        land_total: Optional[int] = None
        if hasattr(self, 'ideal_counts') and getattr(self, 'ideal_counts'):
            basic_min = self.ideal_counts.get('basic_lands')  # type: ignore[attr-defined]
            land_total = self.ideal_counts.get('lands')  # type: ignore[attr-defined]
        if basic_min is None:
            basic_min = getattr(bc, 'DEFAULT_BASIC_LAND_COUNT', 20)
        if land_total is None:
            land_total = getattr(bc, 'DEFAULT_LAND_COUNT', 35)

        # Target basics = 1.3 * minimum (rounded) but not exceeding total lands
        # target_basics = int(round(1.3 * basic_min))
        # if target_basics > land_total:
        #     target_basics = land_total
        # if target_basics <= 0:
        #     self.output_func("Target basic land count is zero; skipping basics.")
        #     return

        # Changing code to use minimum basics as target for simplicity
        target_basics = basic_min

        colors = [c for c in getattr(self, 'color_identity', []) if c in ['W', 'U', 'B', 'R', 'G']]
        if not colors:  # colorless special case -> Wastes only
            colors = []

        # Determine if snow preferred
        selected_tags = getattr(self, 'selected_tags', []) or []
        commander_tags = getattr(self, 'commander_tags', []) or []
        tag_pool = selected_tags + commander_tags
        use_snow = any('snow' in str(t).lower() for t in tag_pool)
        snow_map = getattr(bc, 'SNOW_BASIC_LAND_MAPPING', {})
        basic_map = getattr(bc, 'COLOR_TO_BASIC_LAND', {})

        allocation: Dict[str, int] = {}
        if not colors:  # colorless
            allocation_name = snow_map.get('C', 'Wastes') if use_snow else 'Wastes'
            allocation[allocation_name] = target_basics
        else:
            n = len(colors)
            base = target_basics // n
            rem = target_basics % n
            for idx, c in enumerate(sorted(colors)):  # sorted for deterministic distribution
                count = base + (1 if idx < rem else 0)
                land_name = snow_map.get(c) if use_snow else basic_map.get(c)
                if not land_name:
                    continue
                allocation[land_name] = allocation.get(land_name, 0) + count

        # Add to library
        for land_name, count in allocation.items():
            for _ in range(count):
                # Role metadata: basics (or snow basics)
                self.add_card(
                    land_name,
                    card_type='Land',
                    role='basic',
                    sub_role='snow-basic' if use_snow else 'basic',
                    added_by='lands_step1',
                    trigger_tag='Snow' if use_snow else None
                )

        # Summary output
        self.output_func("\nBasic Lands Added:")
        width = max((len(n) for n in allocation.keys()), default=0)
        for name, cnt in allocation.items():
            self.output_func(f"  {name.ljust(width)} : {cnt}")
        self.output_func(f"  Total Basics : {sum(allocation.values())} (Target {target_basics}, Min {basic_min})")

    def run_land_step1(self):  # type: ignore[override]
        """Public wrapper to execute land building step 1 (basics)."""
        self.add_basic_lands()
        try:
            from .. import builder_utils as _bu
            _bu.export_current_land_pool(self, '1')
        except Exception:
            pass


__all__ = [
    'LandBasicsMixin'
]
