#    Copyright (C) 2025 James Brotosky, Brandon Wickline
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <https://www.gnu.org/licenses/>.

"""
Quiet Agent Workflow Screen Module

Provides a TUI workflow for identifying quiet agents and moving them to target policies.
This screen replaces the legacy quietAgent.py with a comprehensive TUI interface that:
1. Allows selection of an initial policy to analyze
2. Categorizes devices into "Enforce Ready" and "Non-Enforce Ready" based on activity
3. Allows users to select target policies for each category
4. Uses the API to move devices to their target policies
"""

import datetime
import logging
import os
from typing import List, Optional

import pandas as pd
from textual.app import ComposeResult
from textual.containers import Horizontal, Vertical
from textual.reactive import reactive
from textual.screen import Screen
from textual.widgets import Button, DataTable, Footer, Header, Static

from models.policy import Policy
from services.API import AirlockAPIWrapper
from services.policyhandler import getPolicyInfo
from TUI.policyselector import PolicySelector
from utils.configmanager import load_env

logger = logging.getLogger(__name__)


class QuietAgentWorkflowScreen(Screen):
    """
    A Textual screen for the Quiet Agent analysis and migration workflow.

    This screen provides a multi-step workflow:
    1. Select initial policy to analyze
    2. View categorized agents (enforce ready vs. non-enforce ready)
    3. Select target policies for each category
    4. Execute agent migrations

    Attributes:
        api (AirlockAPIWrapper): API wrapper for Airlock operations
        policies (List[Policy]): List of all available policies
        selected_policy (Optional[Policy]): The initially selected policy to analyze
        history_days (int): Number of days of history to pull (default: 150)
        quiet_days (int): Number of days without execution to be considered quiet (default: 45)
        agents_df (Optional[pd.DataFrame]): DataFrame of all agents with analysis results
        enforce_ready_df (Optional[pd.DataFrame]): DataFrame of agents ready for enforcement
        non_enforce_ready_df (Optional[pd.DataFrame]): DataFrame of agents not ready for enforcement
        workflow_stage (str): Current stage of the workflow
    """

    BINDINGS = [
        ("escape", "go_back", "Back"),
    ]

    workflow_stage = reactive("select_policy")  # Tracks current workflow stage

    def __init__(self, api: AirlockAPIWrapper, policies: List[Policy]):
        """
        Initialize the QuietAgentWorkflowScreen.

        Args:
            api (AirlockAPIWrapper): API wrapper for Airlock operations
            policies (List[Policy]): List of all available policies
        """
        super().__init__()
        self.api = api
        self.policies = policies
        self.selected_policy: Optional[Policy] = None
        self.history_days = 150  # Fixed as per requirements
        self.quiet_days = 45  # Default value
        self.agents_df: Optional[pd.DataFrame] = None
        self.enforce_ready_df: Optional[pd.DataFrame] = None
        self.non_enforce_ready_df: Optional[pd.DataFrame] = None
        self.enforce_ready_target_policy: Optional[Policy] = None
        self.non_enforce_ready_target_policy: Optional[Policy] = None

    def compose(self) -> ComposeResult:
        """Build the UI layout for the workflow screen."""
        # Include Header and Footer like other standalone screens
        yield Header(show_clock=True, icon="⚙")

        # Title area
        title = Static("🔒 Quiet Agent Workflow", id="workflow_title")
        title.styles.margin = (0, 0, 0, 1)
        yield title

        # Status area
        status = Static("Step 1: Select Policy to Analyze", id="workflow_status")
        status.styles.margin = (0, 0, 1, 1)
        yield status

        # Content area - dynamically populated based on workflow stage
        yield Vertical(id="content_area")

        yield Footer()

    def on_mount(self) -> None:
        """Initialize the screen when mounted."""
        # Show initial policy selection
        self._show_policy_selection()

    def watch_workflow_stage(self, old_value: str, new_value: str) -> None:
        """React to workflow stage changes."""
        logger.debug(f"Workflow stage changed from {old_value} to {new_value}")
        self._update_status_message()

    def _update_status_message(self) -> None:
        """Update the status message based on current workflow stage."""
        status_widget = self.query_one("#workflow_status", Static)

        stage_messages = {
            "select_policy": "Step 1: Select Policy to Analyze",
            "select_quiet_days": "Step 2: Select Quiet Time Period",
            "analyzing": "📊 Analyzing agent activity...",
            "view_results": "Step 3: Review Categorized Agents",
            "select_enforce_target": "Step 4: Select Target Policy for Enforce Ready Agents",
            "select_non_enforce_target": "Step 5: Select Target Policy for Non-Enforce Ready Agents",
            "confirm_migration": "Step 6: Confirm and Execute Migration",
            "executing": "⏳ Executing agent migrations...",
            "complete": "✅ Migration Complete",
        }

        status_widget.update(stage_messages.get(self.workflow_stage, "Unknown Stage"))

    def _show_policy_selection(self) -> None:
        """Show the initial policy selection screen."""
        self.workflow_stage = "select_policy"
        content = self.query_one("#content_area", Vertical)
        content.remove_children()

        # Create policy selector widget
        policy_selector = PolicySelector(self.policies)
        content.mount(policy_selector)

    def on_policy_selector_policy_selected(
        self, message: PolicySelector.PolicySelected
    ) -> None:
        """Handle policy selection from PolicySelector widget."""
        # Handle based on current workflow stage
        if self.workflow_stage == "select_policy":
            # Initial policy selection for analysis
            self.selected_policy = message.policy
            logger.info(f"Selected policy for analysis: {self.selected_policy.name}")
            self._show_quiet_days_selection()
        elif self.workflow_stage == "select_enforce_target":
            # Target policy selection for enforce ready agents
            self.enforce_ready_target_policy = message.policy
            logger.info(
                f"Selected target policy for enforce ready: {message.policy.name}"
            )
            self._show_non_enforce_target_selection()
        elif self.workflow_stage == "select_non_enforce_target":
            # Target policy selection for non-enforce ready agents
            self.non_enforce_ready_target_policy = message.policy
            logger.info(
                f"Selected target policy for non-enforce ready: {message.policy.name}"
            )
            self._show_migration_confirmation()

    def _show_quiet_days_selection(self) -> None:
        """Show the quiet days selection screen."""
        self.workflow_stage = "select_quiet_days"
        content = self.query_one("#content_area", Vertical)
        content.remove_children()

        # Create info text
        info_widget = Static(
            f"Policy Selected: {self.selected_policy.name}\n\n"
            f"History Period: {self.history_days} days\n\n"
            "Select quiet time period (days without untrusted execution):",
            id="quiet_days_info",
        )
        info_widget.styles.margin = (0, 0, 2, 0)
        content.mount(info_widget)

        # Create button container and mount it first
        button_container = Vertical(id="quiet_days_buttons")
        button_container.styles.height = "auto"
        content.mount(button_container)

        # Now add buttons to the mounted container
        for days in [15, 30, 45, 60]:
            btn = Button(
                f"{days} days {'(Default)' if days == 45 else ''}",
                id=f"quiet_days_{days}",
                classes="quiet_day_btn",
            )
            btn.styles.width = "100%"
            btn.styles.margin = (0, 0, 1, 0)
            button_container.mount(btn)

        back_btn = Button("← Back", id="back_to_policy_selection")
        back_btn.styles.width = "100%"
        back_btn.styles.margin = (2, 0, 0, 0)
        button_container.mount(back_btn)

    def on_button_pressed(self, event: Button.Pressed) -> None:
        """Handle button press events."""
        button_id = event.button.id

        # Quiet days selection buttons
        if button_id and button_id.startswith("quiet_days_"):
            days = int(button_id.split("_")[-1])
            self.quiet_days = days
            logger.info(f"Selected quiet days: {days}")
            self._start_analysis()
            return

        # Navigation buttons
        if button_id == "back_to_policy_selection":
            self._show_policy_selection()
            return

        if button_id == "back_to_results":
            self._show_results()
            return

        if button_id == "select_enforce_target_btn":
            self._show_enforce_target_selection()
            return

        if button_id == "select_non_enforce_target_btn":
            self._show_non_enforce_target_selection()
            return

        if button_id == "skip_enforce_target_btn":
            # Skip enforce ready target selection
            self.enforce_ready_target_policy = None
            self._show_non_enforce_target_selection()
            return

        if button_id == "skip_non_enforce_target_btn":
            # Skip non-enforce ready target selection
            self.non_enforce_ready_target_policy = None
            self._show_migration_confirmation()
            return

        if button_id == "confirm_migration_btn":
            self._execute_migration()
            return

        if button_id == "cancel_migration_btn":
            self._show_results()
            return

        if button_id == "export_results_btn":
            self._export_results()
            return

        if button_id == "start_over_btn":
            self._show_policy_selection()
            return

    def _start_analysis(self) -> None:
        """Start the agent activity analysis."""
        self.workflow_stage = "analyzing"
        content = self.query_one("#content_area", Vertical)
        content.remove_children()

        # Show analyzing message with detailed steps
        analyzing_msg = Static(
            f"📊 Analyzing Agent Activity\n"
            f"{'=' * 50}\n\n"
            f"Policy: {self.selected_policy.name}\n"
            f"History Period: {self.history_days} days\n"
            f"Quiet Threshold: {self.quiet_days} days\n\n"
            f"Progress:\n"
            f"⏳ Step 1/4: Fetching agents from policy...\n"
            f"⏱️  Step 2/4: Pulling execution history (this may take a moment)...\n"
            f"⏱️  Step 3/4: Analyzing activity patterns...\n"
            f"⏱️  Step 4/4: Categorizing agents...\n\n"
            f"Please wait - this operation cannot be cancelled.",
            id="analyzing_message",
        )
        analyzing_msg.styles.margin = (2, 1)
        content.mount(analyzing_msg)

        # Show notification
        self.app.notify(
            "Starting analysis - this may take several minutes for large policies",
            severity="information",
            timeout=5,
        )

        # Perform the analysis asynchronously
        self.call_later(self._perform_analysis)

    def _perform_analysis(self) -> None:
        """Perform the actual agent activity analysis."""
        try:
            # Update status: Fetching agents
            self._update_analysis_status("Step 1/4: Fetching agents from policy...")

            # Get agents in the selected policy
            agents = self.api.agents_find_by_group(self.selected_policy.groupid)

            if agents.empty:
                self.app.notify(
                    f"No agents found in policy: {self.selected_policy.name}",
                    severity="warning",
                    timeout=5,
                )
                self._show_policy_selection()
                return

            agent_count = len(agents)
            self.app.notify(
                f"Found {agent_count} agents - fetching execution history...",
                severity="information",
                timeout=3,
            )

            # Update status: Pulling execution history
            self._update_analysis_status(
                f"Step 2/4: Pulling execution history for {agent_count} agents...\n"
                f"(This may take several minutes - progress shown in terminal)"
            )

            # Get execution history (this shows progress bars in terminal via airlock_libs)
            policy_exec_history = getPolicyInfo(
                self.api, self.selected_policy, [1, 2, 6, 7], self.history_days
            )

            # Update status: Analyzing patterns
            self._update_analysis_status("Step 3/4: Analyzing activity patterns...")
            self.app.notify(
                "History retrieved - analyzing patterns...",
                severity="information",
                timeout=2,
            )

            if policy_exec_history.empty:
                logger.info(
                    "No execution history found for the selected policy and time range."
                )
                # All agents are quiet (no executions)
                agents["execution_count"] = 0
                agents["days_since"] = None
                agents["required_quiet"] = self.quiet_days
                agents["enforce_ready"] = True
            else:
                # Convert datetime column
                policy_exec_history["datetime"] = pd.to_datetime(
                    policy_exec_history["datetime"],
                    format="%Y-%m-%dT%H:%M:%SZ",
                    utc=True,
                )

                # Calculate days ago
                now = datetime.datetime.now(datetime.timezone.utc)
                policy_exec_history["days_ago"] = policy_exec_history["datetime"].apply(
                    lambda dt: (now - dt).days
                )

                # Count total executions per hostname
                hostname_counts = policy_exec_history["hostname"].value_counts()
                agents["execution_count"] = (
                    agents["hostname"].map(hostname_counts).fillna(0).astype(int)
                )

                # Find most recent execution per hostname
                most_recent_exec = policy_exec_history.sort_values(
                    by="days_ago"
                ).drop_duplicates(subset="hostname", keep="first")

                # Map most recent execution age to agents
                agents["days_since"] = agents["hostname"].map(
                    most_recent_exec.set_index("hostname")["days_ago"]
                )

                # Check for enforcement readiness
                agents["required_quiet"] = self.quiet_days
                agents["enforce_ready"] = agents["days_since"].apply(
                    lambda x: True if pd.isna(x) or x > self.quiet_days else False
                )

            # Update status: Categorizing
            self._update_analysis_status("Step 4/4: Categorizing agents...")

            # Sort agents
            agents = agents.sort_values(
                by=["execution_count", "hostname"], ascending=[True, True]
            )

            # Store the results
            self.agents_df = agents

            # Categorize agents into DataFrames
            self.enforce_ready_df = agents[agents["enforce_ready"] == True].copy()
            self.non_enforce_ready_df = agents[agents["enforce_ready"] == False].copy()

            logger.info(
                f"Analysis complete: {len(self.enforce_ready_df)} enforce ready, "
                f"{len(self.non_enforce_ready_df)} non-enforce ready"
            )

            self.app.notify(
                f"Analysis complete! Found {len(self.enforce_ready_df)} enforce ready, "
                f"{len(self.non_enforce_ready_df)} not ready",
                severity="success",
                timeout=5,
            )

            # Show results
            self._show_results()

        except Exception as e:
            logger.error(f"Error during analysis: {e}", exc_info=True)
            self.app.notify(f"Analysis failed: {str(e)}", severity="error", timeout=5)
            self._show_policy_selection()

    def _update_analysis_status(self, status_text: str) -> None:
        """Update the analysis status message."""
        try:
            analyzing_msg = self.query_one("#analyzing_message", Static)

            # Build updated message
            updated_text = (
                f"📊 Analyzing Agent Activity\n"
                f"{'=' * 50}\n\n"
                f"Policy: {self.selected_policy.name}\n"
                f"History Period: {self.history_days} days\n"
                f"Quiet Threshold: {self.quiet_days} days\n\n"
                f"Progress:\n"
                f"✅ {status_text}\n\n"
                f"Please wait - this operation cannot be cancelled."
            )

            analyzing_msg.update(updated_text)
        except Exception as e:
            logger.debug(f"Could not update analysis status: {e}")

    def _show_results(self) -> None:
        """Show the categorized results."""
        self.workflow_stage = "view_results"
        content = self.query_one("#content_area", Vertical)
        content.remove_children()

        # Create results display container and mount it first
        results_container = Vertical(id="results_container")
        results_container.styles.height = "auto"
        results_container.styles.margin = (1, 1)
        content.mount(results_container)

        # Summary statistics
        total_agents = len(self.enforce_ready_df) + len(self.non_enforce_ready_df)
        ready_count = len(self.enforce_ready_df)
        not_ready_count = len(self.non_enforce_ready_df)
        ready_percentage = (ready_count / total_agents * 100) if total_agents > 0 else 0

        summary = Static(
            f"Analysis Results for: {self.selected_policy.name}\n\n"
            f"📊 Total Agents: {total_agents}\n"
            f"✅ Enforce Ready: {ready_count} ({ready_percentage:.1f}%)\n"
            f"❌ Not Ready: {not_ready_count} ({100 - ready_percentage:.1f}%)\n\n"
            f"Quiet Threshold: {self.quiet_days} days\n"
            f"History Period: {self.history_days} days",
            id="results_summary",
        )
        summary.styles.margin = (0, 0, 2, 0)
        results_container.mount(summary)

        # Action buttons
        button_container = Horizontal(id="results_buttons")
        button_container.styles.height = "auto"
        results_container.mount(button_container)

        if ready_count > 0:
            enforce_btn = Button(
                f"Select Target for Enforce Ready ({ready_count})",
                id="select_enforce_target_btn",
            )
            enforce_btn.styles.margin = (0, 1, 1, 0)
            button_container.mount(enforce_btn)

        if not_ready_count > 0:
            non_enforce_btn = Button(
                f"Select Target for Non-Enforce Ready ({not_ready_count})",
                id="select_non_enforce_target_btn",
            )
            non_enforce_btn.styles.margin = (0, 1, 1, 0)
            button_container.mount(non_enforce_btn)

        export_btn = Button("💾 Export Results", id="export_results_btn")
        export_btn.styles.margin = (0, 1, 1, 0)
        button_container.mount(export_btn)

        start_over_btn = Button("🔄 Start Over", id="start_over_btn")
        start_over_btn.styles.margin = (0, 0, 1, 0)
        button_container.mount(start_over_btn)

        # Tables showing agents
        tables_container = Horizontal()
        tables_container.styles.height = "1fr"
        results_container.mount(tables_container)

        # Enforce Ready table
        if ready_count > 0:
            enforce_col = Vertical()
            enforce_col.styles.width = "1fr"
            enforce_col.styles.margin = (1, 1, 0, 0)
            tables_container.mount(enforce_col)

            enforce_label = Static("✅ Enforce Ready Agents")
            enforce_label.styles.margin = (0, 0, 1, 0)
            enforce_col.mount(enforce_label)

            enforce_table = DataTable(id="enforce_ready_table")
            enforce_table.styles.height = "1fr"
            enforce_table.add_columns("Hostname", "Last Exec (days)")

            # Display first 50 agents
            for idx, row in self.enforce_ready_df.head(50).iterrows():
                days_since = row["days_since"]
                days_str = f"{int(days_since)}" if not pd.isna(days_since) else "Never"
                enforce_table.add_row(row["hostname"], days_str)

            if len(self.enforce_ready_df) > 50:
                enforce_table.add_row(
                    f"... and {len(self.enforce_ready_df) - 50} more", ""
                )

            enforce_col.mount(enforce_table)

        # Non-Enforce Ready table
        if not_ready_count > 0:
            non_enforce_col = Vertical()
            non_enforce_col.styles.width = "1fr"
            non_enforce_col.styles.margin = (1, 0, 0, 1)
            tables_container.mount(non_enforce_col)

            non_enforce_label = Static("❌ Non-Enforce Ready Agents")
            non_enforce_label.styles.margin = (0, 0, 1, 0)
            non_enforce_col.mount(non_enforce_label)

            non_enforce_table = DataTable(id="non_enforce_ready_table")
            non_enforce_table.styles.height = "1fr"
            non_enforce_table.add_columns("Hostname", "Last Exec (days)")

            # Display first 50 agents
            for idx, row in self.non_enforce_ready_df.head(50).iterrows():
                days_since = row["days_since"]
                days_str = f"{int(days_since)}" if not pd.isna(days_since) else "N/A"
                non_enforce_table.add_row(row["hostname"], days_str)

            if len(self.non_enforce_ready_df) > 50:
                non_enforce_table.add_row(
                    f"... and {len(self.non_enforce_ready_df) - 50} more", ""
                )

            non_enforce_col.mount(non_enforce_table)

    def _show_enforce_target_selection(self) -> None:
        """Show policy selection for enforce ready agents."""
        self.workflow_stage = "select_enforce_target"
        content = self.query_one("#content_area", Vertical)
        content.remove_children()

        # Info message
        info = Static(
            f"Select target policy for {len(self.enforce_ready_df)} Enforce Ready agents\n"
            f"Source Policy: {self.selected_policy.name}",
            id="enforce_target_info",
        )
        info.styles.margin = (0, 0, 2, 0)
        content.mount(info)

        # Policy selector
        policy_selector = PolicySelector(self.policies)
        content.mount(policy_selector)

        # Skip button
        skip_btn = Button("⭕️ Skip - No Migration", id="skip_enforce_target_btn")
        skip_btn.styles.width = "50%"
        skip_btn.styles.margin = (2, 0, 0, 0)
        content.mount(skip_btn)

    def _show_non_enforce_target_selection(self) -> None:
        """Show policy selection for non-enforce ready agents."""
        self.workflow_stage = "select_non_enforce_target"
        content = self.query_one("#content_area", Vertical)
        content.remove_children()

        # Info message
        info = Static(
            f"Select target policy for {len(self.non_enforce_ready_df)} Non-Enforce Ready agents\n"
            f"Source Policy: {self.selected_policy.name}",
            id="non_enforce_target_info",
        )
        info.styles.margin = (0, 0, 2, 0)
        content.mount(info)

        # Policy selector
        policy_selector = PolicySelector(self.policies)
        content.mount(policy_selector)

        # Skip button
        skip_btn = Button("⭕️ Skip - No Migration", id="skip_non_enforce_target_btn")
        skip_btn.styles.width = "50%"
        skip_btn.styles.margin = (2, 0, 0, 0)
        content.mount(skip_btn)

    def _show_migration_confirmation(self) -> None:
        """Show migration confirmation screen."""
        self.workflow_stage = "confirm_migration"
        content = self.query_one("#content_area", Vertical)
        content.remove_children()

        # Build confirmation message
        confirmation_lines = [
            "🔐 Migration Summary\n",
            f"Source Policy: {self.selected_policy.name}\n",
        ]

        if self.enforce_ready_target_policy:
            confirmation_lines.append(
                f"\n✅ Enforce Ready Migration:\n"
                f"  • Agents: {len(self.enforce_ready_df)}\n"
                f"  • Target: {self.enforce_ready_target_policy.name}\n"
            )

        if self.non_enforce_ready_target_policy:
            confirmation_lines.append(
                f"\n❌ Non-Enforce Ready Migration:\n"
                f"  • Agents: {len(self.non_enforce_ready_df)}\n"
                f"  • Target: {self.non_enforce_ready_target_policy.name}\n"
            )

        if (
            not self.enforce_ready_target_policy
            and not self.non_enforce_ready_target_policy
        ):
            confirmation_lines.append("\n⚠️ No migrations will be performed.")

        confirmation = Static("".join(confirmation_lines), id="migration_confirmation")
        confirmation.styles.margin = (1, 1, 2, 1)
        content.mount(confirmation)

        # Action buttons - mount container first, then add buttons
        button_container = Horizontal(id="confirmation_buttons")
        button_container.styles.height = "auto"
        button_container.styles.margin = (1, 1)
        content.mount(button_container)

        if self.enforce_ready_target_policy or self.non_enforce_ready_target_policy:
            confirm_btn = Button("✅ Confirm Migration", id="confirm_migration_btn")
            confirm_btn.styles.margin = (0, 1, 0, 0)
            button_container.mount(confirm_btn)

        cancel_btn = Button("❌ Cancel", id="cancel_migration_btn")
        button_container.mount(cancel_btn)

    def _execute_migration(self) -> None:
        """Execute the agent migrations."""
        self.workflow_stage = "executing"
        content = self.query_one("#content_area", Vertical)
        content.remove_children()

        # Show executing message
        executing_msg = Static(
            "⏳ Executing agent migrations...\nPlease wait...",
            id="executing_message",
        )
        executing_msg.styles.margin = (2, 1)
        content.mount(executing_msg)

        # Perform migrations asynchronously
        self.call_later(self._perform_migrations)

    def _perform_migrations(self) -> None:
        """Perform the actual agent migrations."""
        successful_migrations = []
        failed_migrations = []

        try:
            # Migrate enforce ready agents
            if self.enforce_ready_target_policy:
                for idx, row in self.enforce_ready_df.iterrows():
                    try:
                        result = self.api.agent_move(
                            row["agentid"], self.enforce_ready_target_policy.groupid
                        )
                        successful_migrations.append(
                            (row["hostname"], self.enforce_ready_target_policy.name)
                        )
                        logger.debug(
                            f"Moved {row['hostname']} to {self.enforce_ready_target_policy.name}"
                        )
                    except Exception as e:
                        failed_migrations.append((row["hostname"], str(e)))
                        logger.error(f"Failed to move {row['hostname']}: {e}")

            # Migrate non-enforce ready agents
            if self.non_enforce_ready_target_policy:
                for idx, row in self.non_enforce_ready_df.iterrows():
                    try:
                        result = self.api.agent_move(
                            row["agentid"], self.non_enforce_ready_target_policy.groupid
                        )
                        successful_migrations.append(
                            (row["hostname"], self.non_enforce_ready_target_policy.name)
                        )
                        logger.debug(
                            f"Moved {row['hostname']} to {self.non_enforce_ready_target_policy.name}"
                        )
                    except Exception as e:
                        failed_migrations.append((row["hostname"], str(e)))
                        logger.error(f"Failed to move {row['hostname']}: {e}")

            # Show completion results
            self._show_completion_results(successful_migrations, failed_migrations)

        except Exception as e:
            logger.error(f"Error during migration execution: {e}", exc_info=True)
            self.app.notify(f"Migration failed: {str(e)}", severity="error", timeout=5)
            self._show_results()

    def _show_completion_results(
        self, successful: List[tuple], failed: List[tuple]
    ) -> None:
        """Show migration completion results."""
        self.workflow_stage = "complete"
        content = self.query_one("#content_area", Vertical)
        content.remove_children()

        # Results summary
        total_attempted = len(successful) + len(failed)
        success_rate = (
            (len(successful) / total_attempted * 100) if total_attempted > 0 else 0
        )

        results = Static(
            f"✅ Migration Complete\n\n"
            f"Total Agents Migrated: {len(successful)}\n"
            f"Failed Migrations: {len(failed)}\n"
            f"Success Rate: {success_rate:.1f}%",
            id="completion_summary",
        )
        results.styles.margin = (1, 1, 2, 1)
        content.mount(results)

        # Details tables
        if successful:
            success_container = Vertical()
            success_container.styles.margin = (0, 1)
            content.mount(success_container)

            success_label = Static("✅ Successful Migrations")
            success_label.styles.margin = (0, 0, 1, 0)
            success_container.mount(success_label)

            success_table = DataTable(id="success_table")
            success_table.styles.height = "auto"
            success_table.add_columns("Hostname", "Target Policy")

            for hostname, target_policy in successful[:25]:  # Show first 25
                success_table.add_row(hostname, target_policy)

            if len(successful) > 25:
                success_table.add_row(f"... and {len(successful) - 25} more", "")

            success_container.mount(success_table)

        if failed:
            failed_container = Vertical()
            failed_container.styles.margin = (2, 1, 0, 1)
            content.mount(failed_container)

            failed_label = Static("❌ Failed Migrations")
            failed_label.styles.margin = (0, 0, 1, 0)
            failed_container.mount(failed_label)

            failed_table = DataTable(id="failed_table")
            failed_table.styles.height = "auto"
            failed_table.add_columns("Hostname", "Error")

            for hostname, error in failed[:25]:  # Show first 25
                failed_table.add_row(hostname, error[:50])  # Truncate error

            if len(failed) > 25:
                failed_table.add_row(f"... and {len(failed) - 25} more", "")

            failed_container.mount(failed_table)

        # Action button
        done_btn = Button("✔ Done", id="start_over_btn")
        done_btn.styles.width = "50%"
        done_btn.styles.margin = (2, 0, 0, 0)
        content.mount(done_btn)

    def _export_results(self) -> None:
        """Export analysis results to CSV."""
        try:
            working_dir = load_env("WORKING_DIR") or os.getcwd()
            filename = os.path.join(
                working_dir,
                f"{self.selected_policy.name}_quiet_analysis_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
            )

            self.agents_df.to_csv(filename, index=False)
            logger.info(f"Exported results to {filename}")
            self.app.notify(
                f"Results exported to:\n{filename}",
                severity="information",
                timeout=5,
            )

        except Exception as e:
            logger.error(f"Failed to export results: {e}")
            self.app.notify(f"Export failed: {str(e)}", severity="error", timeout=5)

    def action_go_back(self) -> None:
        """Handle back/escape action."""
        # Depending on stage, go back to previous stage or exit
        if self.workflow_stage in ["select_policy", "view_results", "complete"]:
            self.app.pop_screen()
        elif self.workflow_stage == "select_quiet_days":
            self._show_policy_selection()
        elif self.workflow_stage == "select_enforce_target":
            self._show_results()
        elif self.workflow_stage == "select_non_enforce_target":
            if self.enforce_ready_target_policy:
                self._show_enforce_target_selection()
            else:
                self._show_results()
        elif self.workflow_stage == "confirm_migration":
            self._show_non_enforce_target_selection()
        else:
            self.app.pop_screen()
