"""BlockBuildersMixin — Block Kit builders and formatting helpers for Slack."""
from __future__ import annotations


class BlockBuildersMixin:
    """Block Kit construction and task/status formatting methods."""

    @staticmethod
    def _format_confirmation_preview(parsed: dict, updated: bool = False) -> str:
        """Format a parsed task as a plain-text confirmation preview (fallback for DMs)."""
        prefix = (
            ":pencil2: *Updated task preview:*" if updated
            else ":clipboard: *Task preview \u2014 react to confirm:*"
        )
        project = parsed.get("project", "?")
        desc = parsed.get("description", "")
        priority = parsed.get("priority", "normal")
        mode = parsed.get("mode", "quick")
        exit_c = parsed.get("exit_criteria") or "\u2014"
        backend = parsed.get("backend") or "claude"

        priority_emoji = {
            "urgent": ":rotating_light:",
            "high": ":arrow_up:",
            "normal": ":white_circle:",
            "low": ":arrow_down:",
        }.get(priority, ":white_circle:")

        target = parsed.get("target") or "mac-local"
        target_emoji = ":large_green_circle:" if target else ":white_circle:"

        lines = [
            prefix,
            f"*Project:* {project}",
            f"*Description:* {desc}",
            f"*Target:* {target_emoji} `{target}`  |  *Backend:* {backend}",
            f"*Priority:* {priority_emoji} {priority}  |  *Mode:* {mode}",
            f"*Exit criteria:* {exit_c}",
            "",
            ":white_check_mark: to submit  |  :x: to cancel  |  Reply to edit",
        ]
        return "\n".join(lines)

    @staticmethod
    def _build_confirmation_blocks(
        parsed: dict, spokes: list[str] | None = None, updated: bool = False
    ) -> list[dict]:
        """Build Block Kit blocks for task confirmation with interactive buttons."""
        prefix = ":pencil2: *Updated task preview:*" if updated else ":clipboard: *Task preview:*"
        project = parsed.get("project", "?")
        desc = parsed.get("description", "")
        priority = parsed.get("priority", "normal")
        mode = parsed.get("mode", "quick")
        exit_c = parsed.get("exit_criteria") or "\u2014"
        backend = parsed.get("backend") or "claude"
        target = parsed.get("target") or "mac-local"

        priority_emoji = {
            "urgent": ":rotating_light:",
            "high": ":arrow_up:",
            "normal": ":white_circle:",
            "low": ":arrow_down:",
        }.get(priority, ":white_circle:")

        blocks: list[dict] = [
            {"type": "section", "text": {"type": "mrkdwn", "text": prefix}},
            {"type": "section", "text": {
                "type": "mrkdwn",
                "text": f"*Project:* {project}\n*Description:* {desc}",
            }},
            {
                "type": "section",
                "fields": [
                    {"type": "mrkdwn", "text": f"*Priority:* {priority_emoji} {priority}"},
                    {"type": "mrkdwn", "text": f"*Mode:* {mode}"},
                    {"type": "mrkdwn", "text": f"*Backend:* {backend}"},
                    {"type": "mrkdwn", "text": f"*Target:* `{target}`"},
                ],
            },
            {"type": "section", "text": {"type": "mrkdwn", "text": f"*Exit criteria:* {exit_c}"}},
        ]

        # Dropdowns for backend and target
        accessory_elements: list[dict] = []

        backend_options = [
            {"text": {"type": "plain_text", "text": b}, "value": b}
            for b in ["claude", "codex"]
        ]
        accessory_elements.append({
            "type": "static_select",
            "action_id": "dobby_select_backend",
            "placeholder": {"type": "plain_text", "text": "Backend"},
            "initial_option": {"text": {"type": "plain_text", "text": backend}, "value": backend},
            "options": backend_options,
        })

        spoke_list = spokes or ["local", "mac-local"]
        target_options = [
            {"text": {"type": "plain_text", "text": s}, "value": s}
            for s in spoke_list
        ]
        # Ensure current target is in options
        if target not in spoke_list:
            target_options.insert(0, {
                "text": {"type": "plain_text", "text": target}, "value": target,
            })
        accessory_elements.append({
            "type": "static_select",
            "action_id": "dobby_select_target",
            "placeholder": {"type": "plain_text", "text": "Target"},
            "initial_option": {"text": {"type": "plain_text", "text": target}, "value": target},
            "options": target_options,
        })

        blocks.append({
            "type": "actions",
            "elements": accessory_elements,
        })

        # Action buttons
        blocks.append({
            "type": "actions",
            "elements": [
                {
                    "type": "button",
                    "action_id": "dobby_submit",
                    "text": {"type": "plain_text", "text": ":white_check_mark: Submit"},
                    "style": "primary",
                },
                {
                    "type": "button",
                    "action_id": "dobby_edit",
                    "text": {"type": "plain_text", "text": ":pencil2: Edit"},
                },
                {
                    "type": "button",
                    "action_id": "dobby_cancel",
                    "text": {"type": "plain_text", "text": ":x: Cancel"},
                    "style": "danger",
                },
            ],
        })

        return blocks

    @staticmethod
    def _format_batch_preview(tasks: list[dict], updated: bool = False) -> str:
        """Format a batch of parsed tasks as a plain-text preview (fallback for DMs)."""
        prefix = (
            ":pencil2: *Updated batch preview:*" if updated
            else ":clipboard: *Batch preview \u2014 react to confirm all:*"
        )
        lines = [prefix, ""]
        for i, parsed in enumerate(tasks, 1):
            project = parsed.get("project", "?")
            desc = parsed.get("description", "")
            priority = parsed.get("priority", "normal")
            lines.append(f"*{i}.* [{project}] {desc} _{priority}_")
        lines.append("")
        lines.append(f":package: {len(tasks)} tasks total")
        lines.append(":white_check_mark: to submit all  |  :x: to cancel  |  Reply to edit")
        return "\n".join(lines)

    @staticmethod
    def _build_batch_preview_blocks(tasks: list[dict], updated: bool = False) -> list[dict]:
        """Build Block Kit blocks for batch confirmation with interactive buttons."""
        prefix = ":pencil2: *Updated batch preview:*" if updated else ":clipboard: *Batch preview:*"
        task_lines = []
        for i, parsed in enumerate(tasks, 1):
            project = parsed.get("project", "?")
            desc = parsed.get("description", "")
            priority = parsed.get("priority", "normal")
            task_lines.append(f"*{i}.* [{project}] {desc} _{priority}_")

        blocks: list[dict] = [
            {"type": "section", "text": {"type": "mrkdwn", "text": prefix}},
            {"type": "section", "text": {"type": "mrkdwn", "text": "\n".join(task_lines)}},
            {"type": "section", "text": {
                "type": "mrkdwn", "text": f":package: {len(tasks)} tasks total",
            }},
            {
                "type": "actions",
                "elements": [
                    {
                        "type": "button",
                        "action_id": "dobby_submit",
                        "text": {"type": "plain_text", "text": ":white_check_mark: Submit All"},
                        "style": "primary",
                    },
                    {
                        "type": "button",
                        "action_id": "dobby_edit",
                        "text": {"type": "plain_text", "text": ":pencil2: Edit"},
                    },
                    {
                        "type": "button",
                        "action_id": "dobby_cancel",
                        "text": {"type": "plain_text", "text": ":x: Cancel"},
                        "style": "danger",
                    },
                ],
            },
        ]
        return blocks

    @staticmethod
    def _build_summary_blocks(
        tasks: list[dict],
        results_map: dict[str, dict],
        project: str | None,
    ) -> list[dict]:
        """Build Slack Block Kit blocks for the overnight summary."""
        completed = [t for t in tasks if t.get("status") == "completed"]
        failed = [t for t in tasks if t.get("status") == "failed"]

        total_cost = 0.0
        for r in results_map.values():
            cost_info = r.get("cost", {})
            total_cost += cost_info.get("cost_usd", 0.0)

        # Header
        label = f" \u2014 *{project}*" if project else ""
        header = f":sunrise: *Overnight Summary{label}*"

        blocks: list[dict] = [
            {"type": "section", "text": {"type": "mrkdwn", "text": header}},
            {
                "type": "section",
                "fields": [
                    {"type": "mrkdwn",
                     "text": f"*Completed:*\n:white_check_mark: {len(completed)}"},
                    {"type": "mrkdwn", "text": f"*Failed:*\n:x: {len(failed)}"},
                    {"type": "mrkdwn", "text": f"*Total Tasks:*\n{len(tasks)}"},
                    {"type": "mrkdwn", "text": f"*Total Cost:*\n${total_cost:.4f}"},
                ],
            },
        ]

        if not tasks:
            blocks.append({
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": "_No tasks completed or failed in the last 12 hours._",
                },
            })
            blocks.append({"type": "divider"})
            blocks.append({
                "type": "context",
                "elements": [{
                    "type": "mrkdwn", "text": ":large_blue_circle: Dobby \u2014 overnight summary",
                }],
            })
            return blocks

        # Completed tasks section
        if completed:
            blocks.append({"type": "divider"})
            blocks.append({
                "type": "section",
                "text": {"type": "mrkdwn", "text": ":white_check_mark: *Completed Tasks*"},
            })
            for t in completed:
                task_id = t.get("id", "?")
                proj = t.get("project", "?")
                desc = t.get("description", "")[:80]
                result = results_map.get(task_id, {})
                summary = result.get("summary", "")[:100]
                cost_usd = result.get("cost", {}).get("cost_usd", 0.0)
                cost_str = f"${cost_usd:.4f}" if cost_usd else "\u2014"

                # Check for git diff stats in metrics
                metrics = result.get("metrics", {})
                diff_stat = ""
                files_changed = metrics.get("files_changed")
                if files_changed is not None:
                    insertions = metrics.get("insertions", 0)
                    deletions = metrics.get("deletions", 0)
                    diff_stat = f" | `+{insertions}/-{deletions}` in {files_changed} files"

                # Check for PR link
                pr_link = ""
                for artifact in result.get("artifacts", []):
                    url = artifact.get("url", "")
                    if "pull" in url or "pr" in url.lower():
                        pr_link = f" | <{url}|PR>"
                        break

                line = f"`{task_id}` [{proj}] {desc}"
                if summary:
                    line += f"\n> {summary}"
                line += f"\n_{cost_str}{diff_stat}{pr_link}_"

                blocks.append({
                    "type": "section",
                    "text": {"type": "mrkdwn", "text": line},
                })

        # Failed tasks section
        if failed:
            blocks.append({"type": "divider"})
            blocks.append({
                "type": "section",
                "text": {"type": "mrkdwn", "text": ":x: *Failed Tasks*"},
            })
            for t in failed:
                task_id = t.get("id", "?")
                proj = t.get("project", "?")
                desc = t.get("description", "")[:80]
                result = results_map.get(task_id, {})
                error = result.get("summary", "No error details")[:150]

                line = f"`{task_id}` [{proj}] {desc}\n> :warning: {error}"
                blocks.append({
                    "type": "section",
                    "text": {"type": "mrkdwn", "text": line},
                })

        blocks.append({"type": "divider"})
        blocks.append({
            "type": "context",
            "elements": [
                {
                    "type": "mrkdwn",
                    "text": ":large_blue_circle: Dobby \u2014 overnight summary"
                    "  |  _Reply with a task ID for details_",
                },
            ],
        })

        return blocks

    @staticmethod
    def _build_task_detail_blocks(task: dict, result: dict | None) -> list[dict]:
        """Build Block Kit blocks for a detailed task drill-down."""
        task_id = task.get("id", "?")
        project = task.get("project", "?")
        description = task.get("description", "")
        status = task.get("status", "?")

        status_emoji = ":white_check_mark:" if status == "completed" else ":x:"
        header = f"{status_emoji} *Task `{task_id}`* \u2014 {project}"

        blocks: list[dict] = [
            {"type": "section", "text": {"type": "mrkdwn", "text": header}},
            {"type": "section", "text": {
                "type": "mrkdwn", "text": f"*Description:*\n{description}",
            }},
        ]

        if result is None:
            blocks.append({
                "type": "section",
                "text": {"type": "mrkdwn", "text": "_No result data available for this task._"},
            })
            return blocks

        summary = result.get("summary", "")
        if summary:
            blocks.append({
                "type": "section",
                "text": {"type": "mrkdwn", "text": f"*Summary:*\n{summary}"},
            })

        # Cost breakdown
        cost_info = result.get("cost", {})
        cost_usd = cost_info.get("cost_usd", 0.0)
        input_tokens = cost_info.get("input_tokens", 0)
        output_tokens = cost_info.get("output_tokens", 0)
        total_tokens = cost_info.get("total_tokens", 0)

        blocks.append({
            "type": "section",
            "fields": [
                {"type": "mrkdwn", "text": f"*Cost:*\n${cost_usd:.4f}"},
                {"type": "mrkdwn", "text": f"*Tokens:*\n{total_tokens:,} total"},
                {"type": "mrkdwn", "text": f"*Input Tokens:*\n{input_tokens:,}"},
                {"type": "mrkdwn", "text": f"*Output Tokens:*\n{output_tokens:,}"},
            ],
        })

        # Metrics (git diff stats, etc.)
        metrics = result.get("metrics", {})
        if metrics:
            metric_lines = []
            for k, v in metrics.items():
                metric_lines.append(f"*{k}:* {v}")
            blocks.append({
                "type": "section",
                "text": {"type": "mrkdwn", "text": "*Metrics:*\n" + "\n".join(metric_lines)},
            })

        # Artifacts
        artifacts = result.get("artifacts", [])
        if artifacts:
            artifact_lines = []
            for a in artifacts:
                a_type = a.get("type", "?")
                url = a.get("url")
                path = a.get("path")
                if url:
                    artifact_lines.append(f"\u2022 {a_type}: <{url}|link>")
                elif path:
                    artifact_lines.append(f"\u2022 {a_type}: `{path}`")
                else:
                    artifact_lines.append(f"\u2022 {a_type}")
            blocks.append({
                "type": "section",
                "text": {"type": "mrkdwn", "text": "*Artifacts:*\n" + "\n".join(artifact_lines)},
            })

        blocks.append({"type": "divider"})
        blocks.append({
            "type": "context",
            "elements": [{
                "type": "mrkdwn",
                "text": f":large_blue_circle: Dobby \u2014 details for `{task_id}`",
            }],
        })

        return blocks

    @staticmethod
    def format_task_response(task_data: dict) -> str:
        """Format a single task dict for display in Slack."""
        tid = task_data.get("id", "?")
        project = task_data.get("project", "?")
        desc = task_data.get("description", "")
        status = task_data.get("status", "?")
        priority = task_data.get("priority", "normal")
        exit_c = task_data.get("exit_criteria") or "\u2014"
        mode = task_data.get("mode", "quick")

        priority_emoji = {
            "urgent": ":rotating_light:",
            "high": ":arrow_up:",
            "normal": ":white_circle:",
            "low": ":arrow_down:",
        }.get(priority, ":white_circle:")

        return (
            f":dobby: *Task `{tid}`* ({project})\n"
            f"> {desc}\n"
            f"*Status:* {status}  |  *Mode:* {mode}  |  *Priority:* {priority_emoji} {priority}\n"
            f"*Exit criteria:* {exit_c}"
        )

    @staticmethod
    def format_status_response(tasks: list) -> str:
        """Format a list of tasks for display in Slack."""
        if not tasks:
            return ":white_check_mark: No tasks found."

        status_emoji = {
            "pending": ":hourglass_flowing_sand:",
            "active": ":arrows_counterclockwise:",
            "running": ":runner:",
            "completed": ":white_check_mark:",
            "failed": ":x:",
            "drafting": ":pencil:",
            "cancelled": ":no_entry_sign:",
        }

        lines = [f":clipboard: *Dobby task status* ({len(tasks)} tasks)\n"]
        for t in tasks:
            emoji = status_emoji.get(t.get("status", ""), ":question:")
            line = (
                f"{emoji} `{t.get('id', '?')}` "
                f"[{t.get('project', '?')}] "
                f"\u2014 {t.get('description', '')[:60]}"
            )
            if t.get("status") in ("running", "active"):
                line += " _(in progress)_"
            lines.append(line)

        return "\n".join(lines)
