"""
Analytics Skill - Metrics, reporting, and performance analysis.
"""

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

logger = logging.getLogger(__name__)


class AnalyticsSkill:
    """
    Handles analytics operations:
    - Sequence funnel metrics
    - Deliverability stats
    - Performance analysis
    - Report generation
    """

    def __init__(self, config: dict):
        self.config = config

    # -------------------------------------------------------------------------
    # Sequence Funnel
    # -------------------------------------------------------------------------

    def calculate_sequence_funnel(
        self,
        sequence_id: str,
        enrollments: list[dict],
        messages: list[dict],
        replies: list[dict],
    ) -> dict:
        """
        Calculate funnel metrics for a sequence.

        Returns:
            {
                "enrolled": int,
                "active": int,
                "sent": int,
                "delivered": int,
                "opened": int,
                "replied": int,
                "positive_replies": int,
                "meetings": int,
                "rates": {...}
            }
        """
        # Filter to this sequence
        seq_enrollments = [e for e in enrollments if e.get("sequence_id") == sequence_id]
        seq_messages = [m for m in messages if m.get("sequence_id") == sequence_id]
        message_ids = {m.get("id") for m in seq_messages if m.get("id")}
        sequence_contact_ids = {e.get("contact_id") for e in seq_enrollments if e.get("contact_id")}
        seq_replies = [
            r for r in replies
            if (r.get("sent_message_id") in message_ids) or (r.get("contact_id") in sequence_contact_ids)
        ]

        # Calculate counts
        enrolled = len(seq_enrollments)
        active = sum(1 for e in seq_enrollments if e.get("status") == "active")
        sent = len(seq_messages)
        delivered = sum(1 for m in seq_messages if not m.get("bounced"))
        opened = sum(1 for m in seq_messages if m.get("opened_at"))
        replied_contacts = {r.get("contact_id") for r in seq_replies if r.get("contact_id")}
        replied = len(replied_contacts)
        positive_contacts = {
            r.get("contact_id")
            for r in seq_replies
            if r.get("intent") in ("interested", "meeting_request", "question") and r.get("contact_id")
        }
        meeting_contacts = {r.get("contact_id") for r in seq_replies if r.get("meeting_requested") and r.get("contact_id")}
        positive_replies = len(positive_contacts)
        meetings = len(meeting_contacts)

        # Calculate rates
        rates = {
            "delivery_rate": delivered / sent if sent > 0 else 0,
            "open_rate": opened / delivered if delivered > 0 else 0,
            "reply_rate": replied / enrolled if enrolled > 0 else 0,
            "positive_rate": positive_replies / replied if replied > 0 else 0,
            "meeting_rate": meetings / enrolled if enrolled > 0 else 0,
        }

        return {
            "sequence_id": sequence_id,
            "enrolled": enrolled,
            "active": active,
            "completed": sum(1 for e in seq_enrollments if e.get("status") == "completed"),
            "sent": sent,
            "delivered": delivered,
            "bounced": sent - delivered,
            "opened": opened,
            "replied": replied,
            "positive_replies": positive_replies,
            "meetings": meetings,
            "rates": rates,
        }

    def calculate_step_performance(
        self,
        sequence: dict,
        messages: list[dict],
        replies: list[dict],
    ) -> list[dict]:
        """Calculate performance for each step in a sequence."""
        steps = sequence.get("steps", [])
        step_metrics = []

        for step in steps:
            step_id = step["id"]
            step_messages = [m for m in messages if m.get("step_id") == step_id]
            step_reply_ids = {m["id"] for m in step_messages}
            step_replies = [r for r in replies if r.get("sent_message_id") in step_reply_ids]

            sent = len(step_messages)
            opened = sum(1 for m in step_messages if m.get("opened_at"))
            replied = len(step_replies)

            step_metrics.append({
                "step_number": step["step_number"],
                "channel": step["channel"],
                "sent": sent,
                "opened": opened,
                "replied": replied,
                "open_rate": opened / sent if sent > 0 else 0,
                "reply_rate": replied / sent if sent > 0 else 0,
            })

        return step_metrics

    # -------------------------------------------------------------------------
    # Deliverability
    # -------------------------------------------------------------------------

    def calculate_deliverability(
        self,
        messages: list[dict],
        days: int = 30,
    ) -> dict:
        """Calculate deliverability metrics."""
        cutoff = datetime.now() - timedelta(days=days)

        recent_messages = []
        for m in messages:
            sent_at = m.get("sent_at")
            if sent_at:
                if isinstance(sent_at, str):
                    sent_at = datetime.fromisoformat(sent_at)
                if sent_at >= cutoff:
                    recent_messages.append(m)

        total = len(recent_messages)
        if total == 0:
            return {
                "period_days": days,
                "total_sent": 0,
                "delivered": 0,
                "bounced": 0,
                "hard_bounces": 0,
                "soft_bounces": 0,
                "delivery_rate": 0,
                "bounce_rate": 0,
            }

        bounced = sum(1 for m in recent_messages if m.get("bounced"))
        hard_bounces = sum(1 for m in recent_messages if m.get("bounce_type") == "hard")
        soft_bounces = sum(1 for m in recent_messages if m.get("bounce_type") == "soft")
        delivered = total - bounced

        return {
            "period_days": days,
            "total_sent": total,
            "delivered": delivered,
            "bounced": bounced,
            "hard_bounces": hard_bounces,
            "soft_bounces": soft_bounces,
            "delivery_rate": delivered / total if total > 0 else 0,
            "bounce_rate": bounced / total if total > 0 else 0,
        }

    # -------------------------------------------------------------------------
    # Reply Analysis
    # -------------------------------------------------------------------------

    def analyze_replies(self, replies: list[dict], days: int = 30) -> dict:
        """Analyze reply patterns and intent distribution."""
        cutoff = datetime.now() - timedelta(days=days)

        recent_replies = []
        for r in replies:
            received_at = r.get("received_at") or r.get("created_at")
            if received_at:
                if isinstance(received_at, str):
                    received_at = datetime.fromisoformat(received_at)
                if received_at >= cutoff:
                    recent_replies.append(r)

        total = len(recent_replies)
        if total == 0:
            return {
                "period_days": days,
                "total_replies": 0,
                "intent_distribution": {},
                "sentiment_distribution": {},
                "objection_distribution": {},
            }

        # Intent distribution
        intent_dist = {}
        for r in recent_replies:
            intent = r.get("intent", "unknown")
            intent_dist[intent] = intent_dist.get(intent, 0) + 1

        # Sentiment distribution
        sentiment_dist = {}
        for r in recent_replies:
            sentiment = r.get("sentiment", "unknown")
            sentiment_dist[sentiment] = sentiment_dist.get(sentiment, 0) + 1

        # Objection distribution
        objection_dist = {}
        for r in recent_replies:
            objection = r.get("objection_type")
            if objection:
                objection_dist[objection] = objection_dist.get(objection, 0) + 1

        return {
            "period_days": days,
            "total_replies": total,
            "intent_distribution": intent_dist,
            "sentiment_distribution": sentiment_dist,
            "objection_distribution": objection_dist,
            "positive_rate": sum(intent_dist.get(i, 0) for i in ["interested", "meeting_request", "question"]) / total if total > 0 else 0,
        }

    # -------------------------------------------------------------------------
    # Prospect Pipeline
    # -------------------------------------------------------------------------

    def calculate_pipeline(self, contacts: list[dict]) -> dict:
        """Calculate prospect pipeline metrics."""
        total = len(contacts)

        status_counts = {}
        for c in contacts:
            status = c.get("status", "new")
            status_counts[status] = status_counts.get(status, 0) + 1

        # ICP score distribution
        score_buckets = {
            "high_fit": 0,      # 80-100
            "good_fit": 0,      # 60-79
            "medium_fit": 0,    # 40-59
            "low_fit": 0,       # 0-39
        }

        for c in contacts:
            score = c.get("icp_score", 0)
            if score >= 80:
                score_buckets["high_fit"] += 1
            elif score >= 60:
                score_buckets["good_fit"] += 1
            elif score >= 40:
                score_buckets["medium_fit"] += 1
            else:
                score_buckets["low_fit"] += 1

        return {
            "total_contacts": total,
            "status_distribution": status_counts,
            "icp_distribution": score_buckets,
            "dnc_count": sum(1 for c in contacts if c.get("dnc")),
            "bounced_count": sum(1 for c in contacts if c.get("bounced")),
            "qualified_count": status_counts.get("qualified", 0),
            "conversion_rate": status_counts.get("qualified", 0) / total if total > 0 else 0,
        }

    # -------------------------------------------------------------------------
    # Report Generation
    # -------------------------------------------------------------------------

    def generate_weekly_report(
        self,
        sequences: list[dict],
        contacts: list[dict],
        enrollments: list[dict],
        messages: list[dict],
        replies: list[dict],
    ) -> str:
        """Generate a markdown weekly report."""
        now = datetime.now()
        week_ago = now - timedelta(days=7)

        # Overall stats
        deliverability = self.calculate_deliverability(messages, days=7)
        reply_analysis = self.analyze_replies(replies, days=7)
        pipeline = self.calculate_pipeline(contacts)

        # Build report
        report = f"""# KIESSCLAW Weekly Report
**Generated**: {now.strftime('%Y-%m-%d %H:%M')}
**Period**: {week_ago.strftime('%Y-%m-%d')} to {now.strftime('%Y-%m-%d')}

---

## Executive Summary

| Metric | Value |
|--------|-------|
| Emails Sent | {deliverability['total_sent']} |
| Delivery Rate | {deliverability['delivery_rate']:.1%} |
| Replies Received | {reply_analysis['total_replies']} |
| Positive Reply Rate | {reply_analysis['positive_rate']:.1%} |
| Pipeline Qualified | {pipeline['qualified_count']} |

---

## Deliverability

- **Sent**: {deliverability['total_sent']}
- **Delivered**: {deliverability['delivered']} ({deliverability['delivery_rate']:.1%})
- **Bounced**: {deliverability['bounced']} ({deliverability['bounce_rate']:.1%})
  - Hard bounces: {deliverability['hard_bounces']}
  - Soft bounces: {deliverability['soft_bounces']}

---

## Reply Analysis

**Total Replies**: {reply_analysis['total_replies']}

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

        report += f"""
---

## Pipeline

- **Total Contacts**: {pipeline['total_contacts']}
- **Qualified**: {pipeline['qualified_count']}
- **DNC**: {pipeline['dnc_count']}
- **Bounced**: {pipeline['bounced_count']}

### Status Distribution
"""
        for status, count in sorted(pipeline['status_distribution'].items(), key=lambda x: -x[1]):
            report += f"- {status}: {count}\n"

        report += f"""
### ICP Score Distribution
- High fit (80-100): {pipeline['icp_distribution']['high_fit']}
- Good fit (60-79): {pipeline['icp_distribution']['good_fit']}
- Medium fit (40-59): {pipeline['icp_distribution']['medium_fit']}
- Low fit (0-39): {pipeline['icp_distribution']['low_fit']}

---

## Active Sequences
"""
        active_sequences = [s for s in sequences if s.get("status") == "active"]
        for seq in active_sequences:
            funnel = self.calculate_sequence_funnel(seq["id"], enrollments, messages, replies)
            report += f"""
### {seq['name']}
- Enrolled: {funnel['enrolled']} | Active: {funnel['active']}
- Sent: {funnel['sent']} | Replied: {funnel['replied']}
- Reply Rate: {funnel['rates']['reply_rate']:.1%}
"""

        report += """
---

*Report generated by KMET (KiessMetrics)*
"""
        return report
