import logging
import re
import uuid
from typing import Dict, Optional

logger = logging.getLogger(__name__)

BOOKING_KEYWORDS = [
    "book",
    "booking",
    "schedule",
    "meeting",
    "appointment",
    "set up",
    "arrange",
    "reserve",
    "confirm the meeting",
]

POSITIVE_KEYWORDS = [
    "yes",
    "sounds good",
    "that works",
    "let's do",
    "sure",
    "i can",
    "i will",
    "i'd like",
    "i would like",
]

CALLBACK_KEYWORDS = [
    "call me later",
    "call back later",
    "call me back",
    "later please",
    "another time",
    "not right now",
    "busy right now",
    "call tomorrow",
    "call back tomorrow",
    "reach me later",
]

DO_NOT_CALL_KEYWORDS = [
    "don't call me",
    "do not call me",
    "stop calling",
    "no more calls",
    "remove me",
    "take me off",
    "don't contact me",
    "stop contacting",
    "never call again",
]

DECLINE_KEYWORDS = [
    "not interested",
    "no thanks",
    "no thank you",
    "i'm not interested",
    "i do not need",
    "i don't need",
    "please don't",
]

FOLLOW_UP_UNCERTAIN = [
    "maybe later",
    "i'll think about it",
    "not sure yet",
    "i need to think",
]

EMAIL_REGEX = re.compile(r"[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}")
TIME_PATTERNS = [
    re.compile(r"\b(?:[01]?\d|2[0-3]):[0-5]\d\b"),  # 14:30 , 9:05
    re.compile(r"\b(?:[1-9]|1[0-2]):[0-5]\d\s?(?:am|pm)\b"),  # 9:30am
    re.compile(r"\b(?:[1-9]|1[0-2])\s?(?:am|pm)\b"),  # 9am
]
DATE_PATTERNS = [
    re.compile(r"\b\d{4}-\d{2}-\d{2}\b"),  # 2025-01-31
    re.compile(r"\b\d{1,2}/\d{1,2}(?:/\d{2,4})?\b"),  # 1/31 or 01/31/2025
    re.compile(
        r"\b("
        r"jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|"
        r"aug(?:ust)?|sep(?:tember)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?"
        r")\s+\d{1,2}(?:st|nd|rd|th)?(?:,\s*\d{4})?\b",
        re.IGNORECASE,
    ),
    re.compile(r"\b(tomorrow|day after tomorrow|next week|next month|next monday|next tuesday|next wednesday|next thursday|next friday)\b", re.IGNORECASE),
]


def _extract_user_text(transcript: str) -> str:
    if not transcript:
        return ""
    lines = []
    for line in transcript.splitlines():
        lower = line.lower().strip()
        if lower.startswith("user:"):
            lines.append(line.split(":", 1)[1].strip())
    return " ".join(lines)


def _extract_match(patterns, text: str) -> Optional[str]:
    for pattern in patterns:
        match = pattern.search(text)
        if match:
            return match.group(0)
    return None


def analyze_call_transcript(transcript: Optional[str]) -> Optional[Dict[str, str]]:
    """
    Analyze raw call transcript text and determine the likely outcome.

    Returns a dictionary with keys:
        - outcome: booking | callback | do_not_call | declined | maybe | no_decision
        - details: human readable summary
        - booking: optional dict with extracted data when outcome == booking
    """
    if not transcript:
        return None

    user_text = _extract_user_text(transcript)
    normalized = re.sub(r"\s+", " ", user_text).strip().lower()

    if not normalized:
        normalized = re.sub(r"\s+", " ", transcript).strip().lower()

    # Detect explicit opt-out first
    for phrase in DO_NOT_CALL_KEYWORDS:
        if phrase in normalized:
            return {
                "outcome": "do_not_call",
                "details": f"Customer requested no further contact (matched phrase: '{phrase}').",
            }

    for phrase in DECLINE_KEYWORDS:
        if phrase in normalized:
            return {
                "outcome": "declined",
                "details": f"Customer declined the offer (matched phrase: '{phrase}').",
            }

    for phrase in CALLBACK_KEYWORDS:
        if phrase in normalized:
            return {
                "outcome": "callback",
                "details": f"Customer requested a follow-up call later (matched phrase: '{phrase}').",
            }

    for phrase in FOLLOW_UP_UNCERTAIN:
        if phrase in normalized:
            return {
                "outcome": "maybe",
                "details": f"Customer expressed uncertainty (matched phrase: '{phrase}').",
            }

    # Booking detection
    has_booking_keyword = any(kw in normalized for kw in BOOKING_KEYWORDS)
    has_positive = any(kw in normalized for kw in POSITIVE_KEYWORDS)
    email_match = EMAIL_REGEX.search(transcript)

    if has_booking_keyword and (has_positive or email_match):
        date_raw = _extract_match(DATE_PATTERNS, transcript)
        time_raw = _extract_match(TIME_PATTERNS, transcript)
        booking_notes = user_text.strip() or transcript.strip()
        details = "Customer agreed to schedule a meeting."
        if not email_match:
            details += " (No email detected.)"
        booking_payload = {
            "customer_email": email_match.group(0).lower() if email_match else None,
            "meeting_date": date_raw,
            "meeting_time": time_raw,
            "notes": booking_notes[:1000],
        }
        return {
            "outcome": "booking",
            "details": details,
            "booking": booking_payload,
        }

    if has_booking_keyword:
        return {
            "outcome": "interested",
            "details": "Customer discussed booking but insufficient details were captured.",
        }

    if normalized:
        return {
            "outcome": "no_decision",
            "details": "Conversation completed without a clear follow-up action.",
        }

    return None


def process_call_outcome(cursor, campaign_call_id, transcript):
    """
    Analyze transcript, update campaign_calls outcome fields, and create booking entries.
    """
    try:
        result = analyze_call_transcript(transcript)
        if not result:
            return

        outcome = result.get("outcome")
        details = result.get("details")

        if outcome:
            cursor.execute(
                """
                UPDATE campaign_calls
                SET outcome = %s,
                    outcome_details = %s
                WHERE id = %s
                """,
                (outcome, details, campaign_call_id),
            )

        if outcome == "booking":
            booking = result.get("booking", {})
            cursor.execute(
                """
                SELECT cc.contact_id, c.company_id
                FROM campaign_calls cc
                JOIN call_campaigns c ON cc.campaign_id = c.id
                WHERE cc.id = %s
                """,
                (campaign_call_id,),
            )
            row = cursor.fetchone()
            if not row:
                logger.warning("Unable to resolve contact/company for campaign_call_id %s", campaign_call_id)
                return

            contact_id, company_id = row
            booking_id = str(uuid.uuid4())
            cursor.execute(
                """
                INSERT INTO bookings (
                    id,
                    company_id,
                    contact_id,
                    campaign_call_id,
                    outcome,
                    customer_email,
                    meeting_date_raw,
                    meeting_time_raw,
                    additional_details
                ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
                ON DUPLICATE KEY UPDATE
                    outcome = VALUES(outcome),
                    customer_email = VALUES(customer_email),
                    meeting_date_raw = VALUES(meeting_date_raw),
                    meeting_time_raw = VALUES(meeting_time_raw),
                    additional_details = VALUES(additional_details)
                """,
                (
                    booking_id,
                    str(company_id),
                    str(contact_id),
                    str(campaign_call_id),
                    outcome,
                    booking.get("customer_email"),
                    booking.get("meeting_date"),
                    booking.get("meeting_time"),
                    booking.get("notes"),
                ),
            )
    except Exception as exc:
        logger.error("Failed to process call outcome for campaign_call_id %s: %s", campaign_call_id, exc, exc_info=True)

