"""
KINB - KiessInbox Agent
Handles reply classification, qualification, and DNC management.
"""

from __future__ import annotations
import logging
from datetime import datetime
from typing import Optional

from ..core.agent import BaseAgent
from ..core.memory import MemoryEngine
from ..integrations import SlackIntegration
from ..skills.inbox import InboxSkill

logger = logging.getLogger(__name__)


class KiessInboxAgent(BaseAgent):
    """
    Inbox agent responsible for:
    - Classifying reply intent
    - Managing DNC lists
    - Suggesting next actions
    - Updating contact qualification status
    """

    codename = "KINB"
    name = "KiessInbox"
    description = "Reply parsing, classification, CRM sync"

    def __init__(self, config: dict, memory: MemoryEngine):
        super().__init__(config, memory)
        self.inbox_skill = InboxSkill(config)
        slack_cfg = config.get("slack", {}) if isinstance(config, dict) else {}
        slack_enabled = bool(slack_cfg.get("enabled", False)) if isinstance(slack_cfg, dict) else False
        self.slack = SlackIntegration(
            webhook_url=slack_cfg.get("webhook_url") if slack_enabled else None,
            bot_token=slack_cfg.get("bot_token") if isinstance(slack_cfg, dict) else None,
        )

    def run(self, task: str, **kwargs) -> str:
        """
        Execute an inbox task.

        Supported tasks:
        - classify: Classify a reply
        - process: Process all unprocessed replies
        - dnc: Manage DNC list
        - status: Get inbox status
        """
        self.update_status("running", task)

        try:
            if task == "classify" or "classify" in task.lower():
                return self._handle_classify(**kwargs)
            elif task == "process" or "process" in task.lower():
                return self._handle_process(**kwargs)
            elif task == "dnc" or "dnc" in task.lower():
                return self._handle_dnc(**kwargs)
            elif task == "status" or "status" in task.lower():
                return self._handle_status(**kwargs)
            else:
                return self._handle_natural_language(task, **kwargs)

        except Exception as e:
            logger.error(f"[KINB] Error: {e}")
            self.update_status("error", task)
            return f"Error: {str(e)}"

        finally:
            self.update_status("idle")

    def _handle_classify(
        self,
        reply_text: str = None,
        reply_id: str = None,
        **kwargs
    ) -> str:
        """Classify a single reply."""
        if not reply_text and not reply_id:
            return "Error: reply_text or reply_id required"

        # If reply_id provided, load from data
        if reply_id:
            replies = self.memory.load_data("replies")
            for r in replies:
                if r["id"] == reply_id:
                    reply_text = r["raw_text"]
                    break

        if not reply_text:
            return f"Reply {reply_id} not found"

        # Try rule-based classification first
        rule_result = self.inbox_skill.classify_with_rules(reply_text)

        if rule_result and rule_result["confidence"] >= self.inbox_skill.classification_threshold:
            classification = rule_result
        else:
            # Use LLM for classification
            prompt = self.inbox_skill.build_classification_prompt(reply_text)
            response = self.think(user_message=prompt)
            classification = self.inbox_skill.parse_classification_response(response.content)

        # Get next action suggestion
        next_action = self.inbox_skill.suggest_next_action(classification)

        # Log
        self.memory.log(
            "kinb",
            f"**Classified Reply**\n"
            f"- Intent: {classification['intent']}\n"
            f"- Confidence: {classification['confidence']:.2f}\n"
            f"- Sentiment: {classification['sentiment']}\n"
            f"- Next action: {next_action['action']}"
        )

        # Format output
        output = f"**Reply Classification**\n\n"
        output += f"Intent: **{classification['intent']}** ({classification['confidence']:.0%})\n"
        output += f"Sentiment: {classification['sentiment']}\n"

        if classification['objection_type']:
            output += f"Objection: {classification['objection_type']}\n"

        if classification['meeting_requested']:
            output += "Meeting requested: Yes\n"

        if classification['referral_name']:
            output += f"Referral: {classification['referral_name']}"
            if classification['referral_email']:
                output += f" ({classification['referral_email']})"
            output += "\n"

        output += f"\n**Next Action:** {next_action['action']}\n"
        output += f"Priority: {next_action['priority']}\n"
        output += f"Details: {next_action['details']}"

        return output

    def _handle_process(self, limit: int = 50, **kwargs) -> str:
        """Process all unprocessed replies."""
        replies = self.memory.load_data("replies")
        contacts = self.memory.load_data("contacts")
        enrollments = self.memory.load_data("enrollments")

        # Find unprocessed replies
        unprocessed = [r for r in replies if not r.get("processed")]

        if not unprocessed:
            return "No unprocessed replies found"

        processed_count = 0
        results = []

        for reply in unprocessed[:limit]:
            reply_text = reply.get("raw_text", "")

            # Try rule-based first
            rule_result = self.inbox_skill.classify_with_rules(reply_text)

            if rule_result and rule_result["confidence"] >= self.inbox_skill.classification_threshold:
                classification = rule_result
            else:
                prompt = self.inbox_skill.build_classification_prompt(reply_text)
                response = self.think(user_message=prompt)
                classification = self.inbox_skill.parse_classification_response(response.content)

            # Update reply record
            reply["intent"] = classification["intent"]
            reply["intent_confidence"] = classification["confidence"]
            reply["objection_type"] = classification.get("objection_type")
            reply["sentiment"] = classification.get("sentiment")
            reply["meeting_requested"] = classification.get("meeting_requested", False)
            reply["referral_name"] = classification.get("referral_name")
            reply["referral_email"] = classification.get("referral_email")
            reply["processed"] = True
            reply["processed_at"] = datetime.now().isoformat()
            reply["processed_by"] = "KINB"

            # Get next action
            next_action = self.inbox_skill.suggest_next_action(classification)
            reply["next_action"] = next_action["action"]

            # Optional Slack notification for classified replies.
            contact_id = reply.get("contact_id")
            contact_email = None
            contact_name = ""
            for contact in contacts:
                if contact["id"] == contact_id:
                    contact_email = contact.get("email")
                    contact_name = f"{contact.get('first_name', '')} {contact.get('last_name', '')}".strip()
                    break
            self.slack.notify(
                "reply_received",
                {
                    "contact": contact_name or contact_email or "Unknown contact",
                    "intent": classification.get("intent", "unknown"),
                    "text_preview": reply_text,
                },
            )

            # Handle DNC
            if self.inbox_skill.should_add_to_dnc(classification["intent"]):
                for contact in contacts:
                    if contact["id"] == contact_id:
                        contact["dnc"] = True
                        contact["dnc_reason"] = self.inbox_skill.get_dnc_reason(
                            classification["intent"],
                            classification.get("objection_type")
                        )
                        contact["status"] = "disqualified"
                        break

                # Stop sequences
                self._stop_contact_sequences(enrollments, contact_id, reason="unsubscribe")

            # Update contact status based on intent
            elif classification["intent"] in ("interested", "meeting_request"):
                for contact in contacts:
                    if contact["id"] == contact_id:
                        contact["status"] = "qualified"
                        contact["last_replied_at"] = datetime.now().isoformat()
                        contact["reply_count"] = contact.get("reply_count", 0) + 1
                        break
                self._stop_contact_sequences(enrollments, contact_id, reason="reply")
            else:
                # Neutral/negative replies still stop future sequence sends for the contact.
                if contact_id:
                    for contact in contacts:
                        if contact["id"] == contact_id:
                            contact["last_replied_at"] = datetime.now().isoformat()
                            contact["reply_count"] = contact.get("reply_count", 0) + 1
                            break
                    self._stop_contact_sequences(enrollments, contact_id, reason="reply")

            processed_count += 1
            results.append({
                "reply_id": reply["id"],
                "intent": classification["intent"],
                "action": next_action["action"],
            })

        # Save all data
        self.memory.save_data("replies", replies)
        self.memory.save_data("contacts", contacts)
        self.memory.save_data("enrollments", enrollments)

        # Log summary
        intent_counts = {}
        for r in results:
            intent = r["intent"]
            intent_counts[intent] = intent_counts.get(intent, 0) + 1

        self.memory.log(
            "kinb",
            f"**Batch Processing Complete**\n"
            f"- Processed: {processed_count}\n"
            f"- Intent breakdown: {intent_counts}"
        )

        output = f"**Processed {processed_count} Replies**\n\n"
        output += "Intent breakdown:\n"
        for intent, count in sorted(intent_counts.items(), key=lambda x: -x[1]):
            output += f"- {intent}: {count}\n"

        return output

    def _handle_dnc(
        self,
        action: str = "list",
        email: str = None,
        reason: str = None,
        **kwargs
    ) -> str:
        """Manage DNC list."""
        contacts = self.memory.load_data("contacts")

        if action == "list":
            dnc_contacts = [c for c in contacts if c.get("dnc")]
            if not dnc_contacts:
                return "No contacts on DNC list"

            output = f"**DNC List ({len(dnc_contacts)} contacts)**\n\n"
            for c in dnc_contacts[:20]:
                output += f"- {c['email']}: {c.get('dnc_reason', 'N/A')}\n"

            if len(dnc_contacts) > 20:
                output += f"\n...and {len(dnc_contacts) - 20} more"

            return output

        elif action == "add" and email:
            for contact in contacts:
                if contact["email"] == email:
                    contact["dnc"] = True
                    contact["dnc_reason"] = reason or "Manual DNC"
                    contact["status"] = "disqualified"
                    self.memory.save_data("contacts", contacts)
                    return f"Added {email} to DNC list"

            return f"Contact {email} not found"

        elif action == "remove" and email:
            for contact in contacts:
                if contact["email"] == email:
                    contact["dnc"] = False
                    contact["dnc_reason"] = None
                    self.memory.save_data("contacts", contacts)
                    return f"Removed {email} from DNC list"

            return f"Contact {email} not found"

        elif action == "check" and email:
            for contact in contacts:
                if contact["email"] == email:
                    if contact.get("dnc"):
                        return f"{email} IS on DNC list. Reason: {contact.get('dnc_reason')}"
                    else:
                        return f"{email} is NOT on DNC list"

            return f"Contact {email} not found"

        return "Usage: dnc action=[list|add|remove|check] email=... reason=..."

    def _handle_status(self, **kwargs) -> str:
        """Get inbox processing status."""
        replies = self.memory.load_data("replies")

        total = len(replies)
        processed = sum(1 for r in replies if r.get("processed"))
        unprocessed = total - processed

        # Intent distribution
        intent_counts = {}
        for r in replies:
            if r.get("processed"):
                intent = r.get("intent", "unknown")
                intent_counts[intent] = intent_counts.get(intent, 0) + 1

        output = f"**Inbox Status**\n\n"
        output += f"Total replies: {total}\n"
        output += f"Processed: {processed}\n"
        output += f"Pending: {unprocessed}\n\n"

        if intent_counts:
            output += "**Intent Distribution**\n"
            for intent, count in sorted(intent_counts.items(), key=lambda x: -x[1]):
                pct = count / processed * 100 if processed > 0 else 0
                output += f"- {intent}: {count} ({pct:.1f}%)\n"

        return output

    def _handle_natural_language(self, task: str, **kwargs) -> str:
        """Handle natural language requests."""
        replies = self.memory.load_data("replies")

        context = f"Replies in inbox: {len(replies)}\nUnprocessed: {sum(1 for r in replies if not r.get('processed'))}"

        response = self.think(
            user_message=task,
            context=context,
        )

        return response.content

    def _stop_contact_sequences(self, enrollments: list[dict], contact_id: str, reason: str) -> None:
        """Mark all active/pending enrollments as replied and cancel future sends."""
        for enrollment in enrollments:
            if enrollment.get("contact_id") != contact_id:
                continue
            if enrollment.get("status") in {"completed", "bounced"}:
                continue

            enrollment["status"] = "replied"
            enrollment["next_send_at"] = None
            enrollment["replied_at"] = datetime.now().isoformat()
            enrollment["stop_reason"] = reason
