"""SlidePlanner agent — converts a topic and context into a structured slide plan."""

from __future__ import annotations

from typing import Optional

from pydantic import BaseModel, Field

from pptx_mcp.agents.archetypes import ARCHETYPES
from pptx_mcp.agents.base import BaseAgent
from pptx_mcp.agents.content_mapper import suggest_slide_type
from pptx_mcp.models.slides import (
    AgendaItem,
    ColumnContent,
    FunnelStage,
    IconItem,
    KpiCard,
    PresentationDefinition,
    PresentationMetadata,
    ProcessStep,
    SlideDefinition,
    SlideType,
    SwotData,
    TeamMember,
)


class PlannerInput(BaseModel):
    """Input for the SlidePlanner agent."""

    topic: str = Field(description="Main topic or title of the presentation")
    audience: str = Field(default="executive", description="Target audience")
    num_slides: int = Field(default=10, ge=3, le=50, description="Target number of slides")
    key_points: list[str] = Field(default_factory=list, description="Key points to cover")
    context: str = Field(default="", description="Additional context or instructions")
    include_agenda: bool = Field(default=True, description="Include an agenda slide")
    include_summary: bool = Field(default=True, description="Include a summary/closing slide")
    author: Optional[str] = None
    company: Optional[str] = None
    deck_type: Optional[str] = Field(default=None, description="Deck archetype name (e.g. 'pitch_deck', 'board_deck')")


class SlidePlannerAgent(BaseAgent[PlannerInput, PresentationDefinition]):
    """Generates a structured slide plan from a topic description."""

    @property
    def name(self) -> str:
        return "slide_planner"

    @property
    def description(self) -> str:
        return "Converts a topic and context into a structured slide plan."

    def run(self, input_data: PlannerInput) -> PresentationDefinition:
        self.logger.info("Planning presentation: '%s' (%d slides)", input_data.topic, input_data.num_slides)

        if input_data.deck_type and input_data.deck_type in ARCHETYPES:
            slides = self._plan_from_archetype(input_data)
        elif input_data.key_points:
            slides = self._plan_from_key_points_smart(input_data)
        else:
            slides = self._plan_default(input_data)

        # Enforce variety and structure
        slides = self._enforce_variety(slides)

        metadata = PresentationMetadata(
            title=input_data.topic,
            author=input_data.author,
            company=input_data.company,
            subject=input_data.topic,
        )

        return PresentationDefinition(metadata=metadata, slides=slides)

    def _plan_from_archetype(self, input_data: PlannerInput) -> list[SlideDefinition]:
        """Plan slides from a deck archetype."""
        archetype = ARCHETYPES[input_data.deck_type]  # type: ignore[index]
        target = max(archetype.min_slides, min(input_data.num_slides, archetype.max_slides))

        slots = list(archetype.slots)

        # Scale: if target > slots, repeat optional/content slots
        slides: list[SlideDefinition] = []
        for slot in slots:
            title = slot.title_template
            slide = self._create_skeleton_slide(slot.slide_type, title, len(slides))
            slides.append(slide)

        # Fill remaining budget with CONTENT slides
        while len(slides) < target:
            idx = len(slides)
            slides.insert(-1, self._create_skeleton_slide(
                SlideType.CONTENT,
                f"Detail Slide {idx}",
                idx,
            ))

        # Trim if over budget (keep first, last, and evenly spaced)
        if len(slides) > target:
            first = slides[0]
            last = slides[-1]
            middle = slides[1:-1]
            step = max(1, len(middle) // (target - 2))
            kept = middle[::step][:target - 2]
            slides = [first] + kept + [last]

        return slides[:target]

    def _plan_from_key_points_smart(self, input_data: PlannerInput) -> list[SlideDefinition]:
        """Plan content slides using content-aware type selection."""
        slides: list[SlideDefinition] = []

        # Title
        slides.append(SlideDefinition(
            slide_type=SlideType.TITLE,
            title=input_data.topic,
            subtitle=self._generate_subtitle(input_data),
            speaker_notes="Introduce the topic and set expectations.",
        ))

        # Agenda
        if input_data.include_agenda:
            slides.append(SlideDefinition(
                slide_type=SlideType.AGENDA,
                title="Agenda",
                agenda_items=[AgendaItem(title=kp) for kp in input_data.key_points[:8]],
                speaker_notes="Walk through what we'll cover today.",
            ))

        # Content budget
        content_budget = input_data.num_slides - len(slides)
        if input_data.include_summary:
            content_budget -= 1

        for i, point in enumerate(input_data.key_points[:content_budget]):
            if i > 0 and i % 4 == 0:
                slides.append(SlideDefinition(
                    slide_type=SlideType.SECTION,
                    title=point,
                    speaker_notes=f"Transition to: {point}",
                ))
                continue

            stype = suggest_slide_type(point, input_data.context)
            slide = self._create_skeleton_slide(stype, point, i)
            slides.append(slide)

        # Fill remaining
        while len(slides) < input_data.num_slides - (1 if input_data.include_summary else 0):
            slides.append(self._create_skeleton_slide(
                SlideType.CONTENT,
                f"Additional Detail {len(slides)}",
                len(slides),
            ))

        # Closing
        if input_data.include_summary:
            slides.append(SlideDefinition(
                slide_type=SlideType.CLOSING,
                title="Key Takeaways",
                subtitle="Thank you for your time.",
                speaker_notes="Summarize key points and call to action.",
            ))

        return slides

    def _plan_default(self, input_data: PlannerInput) -> list[SlideDefinition]:
        """Plan slides with a varied default structure."""
        slides: list[SlideDefinition] = []

        # Title
        slides.append(SlideDefinition(
            slide_type=SlideType.TITLE,
            title=input_data.topic,
            subtitle=self._generate_subtitle(input_data),
            speaker_notes="Introduce the topic and set expectations.",
        ))

        # Agenda
        if input_data.include_agenda:
            agenda_items = self._generate_agenda(input_data)
            slides.append(SlideDefinition(
                slide_type=SlideType.AGENDA,
                title="Agenda",
                agenda_items=[AgendaItem(title=item) for item in agenda_items],
                speaker_notes="Walk through what we'll cover today.",
            ))

        content_budget = input_data.num_slides - len(slides)
        if input_data.include_summary:
            content_budget -= 1

        structure = self._get_default_structure(content_budget)
        for i, (stype, title_template) in enumerate(structure):
            title = title_template.format(topic=input_data.topic)
            slide = self._create_skeleton_slide(stype, title, i)
            slides.append(slide)

        # Closing
        if input_data.include_summary:
            slides.append(SlideDefinition(
                slide_type=SlideType.CLOSING,
                title="Key Takeaways",
                subtitle="Thank you for your time.",
                speaker_notes="Summarize key points and call to action.",
            ))

        return slides

    def _enforce_variety(self, slides: list[SlideDefinition]) -> list[SlideDefinition]:
        """Ensure no 3+ consecutive identical non-SECTION types."""
        if len(slides) < 3:
            return slides

        result = list(slides)
        i = 2
        while i < len(result):
            if (
                result[i].slide_type == result[i - 1].slide_type == result[i - 2].slide_type
                and result[i].slide_type not in (SlideType.SECTION, SlideType.TITLE)
            ):
                # Insert a section break before the third consecutive
                result.insert(i, SlideDefinition(
                    slide_type=SlideType.SECTION,
                    title="[Section Break]",
                    speaker_notes="Section break for visual variety.",
                ))
                i += 2  # skip past the inserted section
            else:
                i += 1

        return result

    def _generate_subtitle(self, input_data: PlannerInput) -> str:
        parts: list[str] = []
        if input_data.company:
            parts.append(input_data.company)
        if input_data.audience == "executive":
            parts.append("Executive Overview")
        elif input_data.audience == "technical":
            parts.append("Technical Deep Dive")
        else:
            parts.append("Overview")
        return " | ".join(parts) if parts else "Overview"

    def _generate_agenda(self, input_data: PlannerInput) -> list[str]:
        if input_data.key_points:
            return input_data.key_points[:6]
        return [
            "Background & Context",
            "Current State Analysis",
            "Proposed Approach",
            "Key Considerations",
            "Next Steps",
        ]

    def _get_default_structure(self, budget: int) -> list[tuple[SlideType, str]]:
        full_structure: list[tuple[SlideType, str]] = [
            (SlideType.SECTION, "Background"),
            (SlideType.CONTENT, "Current State"),
            (SlideType.TWO_COLUMN, "Analysis"),
            (SlideType.BIG_NUMBER, "Key Metric"),
            (SlideType.SECTION, "Approach"),
            (SlideType.CONTENT, "Proposed Solution"),
            (SlideType.PROS_CONS, "Trade-offs"),
            (SlideType.CHART, "Impact & Metrics"),
            (SlideType.DASHBOARD, "Performance Overview"),
            (SlideType.SECTION, "Path Forward"),
            (SlideType.PROCESS, "Implementation Plan"),
            (SlideType.TIMELINE, "Timeline & Resources"),
            (SlideType.COMPARISON, "Options Comparison"),
            (SlideType.QUOTE, "Expert Perspective"),
        ]

        if budget <= len(full_structure):
            step = max(1, len(full_structure) // budget)
            return full_structure[::step][:budget]

        result = list(full_structure)
        while len(result) < budget:
            result.append((SlideType.CONTENT, f"Detail Slide {len(result) + 1}"))
        return result[:budget]

    def _create_skeleton_slide(self, slide_type: SlideType, title: str, index: int) -> SlideDefinition:
        """Create a skeleton slide with placeholder content for any of the 23 types."""
        if slide_type == SlideType.SECTION:
            return SlideDefinition(slide_type=slide_type, title=title, speaker_notes=f"Transition: {title}")

        if slide_type == SlideType.TWO_COLUMN:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                columns=[
                    ColumnContent(title="Column A", bullets=["[Point 1]", "[Point 2]", "[Point 3]"]),
                    ColumnContent(title="Column B", bullets=["[Point 1]", "[Point 2]", "[Point 3]"]),
                ],
                speaker_notes=f"Discuss {title} from two perspectives.",
            )

        if slide_type == SlideType.PROS_CONS:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                pros=["[Advantage 1]", "[Advantage 2]", "[Advantage 3]"],
                cons=["[Disadvantage 1]", "[Disadvantage 2]", "[Disadvantage 3]"],
                speaker_notes=f"Weigh the pros and cons of {title}.",
            )

        if slide_type == SlideType.COMPARISON:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                columns=[
                    ColumnContent(title="Option A", bullets=["[Feature 1]", "[Feature 2]"]),
                    ColumnContent(title="Option B", bullets=["[Feature 1]", "[Feature 2]"]),
                    ColumnContent(title="Option C", bullets=["[Feature 1]", "[Feature 2]"]),
                ],
                speaker_notes=f"Compare options for {title}.",
            )

        if slide_type == SlideType.QUOTE:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                body="[Notable quote or testimonial]",
                quote_attribution="[Speaker Name]",
                quote_attribution_role="[Role/Title]",
            )

        if slide_type == SlideType.BIG_NUMBER:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                body="[XX%]",
                subtitle="[Context for the number]",
                bullets=["[Comparison or change from prior period]"],
            )

        if slide_type == SlideType.PROCESS:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                steps=[
                    ProcessStep(title="Step 1", description="[Description]", status="completed"),
                    ProcessStep(title="Step 2", description="[Description]", status="active"),
                    ProcessStep(title="Step 3", description="[Description]", status="future"),
                ],
                active_step=1,
            )

        if slide_type == SlideType.TIMELINE:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                steps=[
                    ProcessStep(title="Phase 1", date="[Date]", status="completed"),
                    ProcessStep(title="Phase 2", date="[Date]", status="active"),
                    ProcessStep(title="Phase 3", date="[Date]", status="future"),
                ],
            )

        if slide_type == SlideType.STEP_CARDS:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                steps=[
                    ProcessStep(title="Step 1", description="[Description]"),
                    ProcessStep(title="Step 2", description="[Description]"),
                    ProcessStep(title="Step 3", description="[Description]"),
                ],
            )

        if slide_type == SlideType.DASHBOARD:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                kpis=[
                    KpiCard(value="[XX]", label="[Metric 1]", change="[+X%]", trend="up"),
                    KpiCard(value="[XX]", label="[Metric 2]", change="[+X%]", trend="up"),
                    KpiCard(value="[XX]", label="[Metric 3]", trend="neutral"),
                    KpiCard(value="[XX]", label="[Metric 4]", change="[-X%]", trend="down"),
                ],
            )

        if slide_type == SlideType.ICON_GRID:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                icons=[
                    IconItem(icon="\u2605", title="[Item 1]", description="[Description]"),
                    IconItem(icon="\u2605", title="[Item 2]", description="[Description]"),
                    IconItem(icon="\u2605", title="[Item 3]", description="[Description]"),
                    IconItem(icon="\u2605", title="[Item 4]", description="[Description]"),
                ],
            )

        if slide_type == SlideType.IMAGE_TEXT:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                body="[Description of the visual content]",
                bullets=["[Key point 1]", "[Key point 2]"],
                image_position="left",
            )

        if slide_type == SlideType.TEAM:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                team_members=[
                    TeamMember(name="[Name 1]", role="[Role]"),
                    TeamMember(name="[Name 2]", role="[Role]"),
                    TeamMember(name="[Name 3]", role="[Role]"),
                ],
            )

        if slide_type == SlideType.CLOSING:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                subtitle="[Closing message]",
                speaker_notes="Summarize and close.",
            )

        if slide_type == SlideType.SWOT:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                swot=SwotData(
                    strengths=["[Strength 1]", "[Strength 2]"],
                    weaknesses=["[Weakness 1]", "[Weakness 2]"],
                    opportunities=["[Opportunity 1]", "[Opportunity 2]"],
                    threats=["[Threat 1]", "[Threat 2]"],
                ),
            )

        if slide_type == SlideType.FUNNEL:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                funnel_stages=[
                    FunnelStage(label="[Stage 1]", value="[Value]"),
                    FunnelStage(label="[Stage 2]", value="[Value]"),
                    FunnelStage(label="[Stage 3]", value="[Value]"),
                ],
            )

        if slide_type == SlideType.AGENDA:
            return SlideDefinition(
                slide_type=slide_type, title=title,
                agenda_items=[
                    AgendaItem(title="[Topic 1]"),
                    AgendaItem(title="[Topic 2]"),
                    AgendaItem(title="[Topic 3]"),
                ],
            )

        # Default: CONTENT (also handles CHART, TABLE, DIAGRAM, BLANK, TITLE)
        return SlideDefinition(
            slide_type=slide_type, title=title,
            bullets=["[Key point 1]", "[Key point 2]", "[Key point 3]"],
            speaker_notes=f"Cover the key aspects of {title}.",
        )

    def _generate_takeaways(self, input_data: PlannerInput) -> list[str]:
        if input_data.key_points:
            return [f"[Takeaway for: {p}]" for p in input_data.key_points[:4]]
        return ["[Key takeaway 1]", "[Key takeaway 2]", "[Key takeaway 3]", "[Call to action]"]
