from typing import Tuple
from models.ring_central_models import (
    RingCentralSession,
    RingCentralNotification,
    RingCentralMethods,
)
from models.department_models import DepartmentOperations
from models.call_actions_models import (
    CallActionOperations,
    CreateCallActionInput,
    CallActionPriority,
    CallActionType,
    CallActionStatus,
)
from ff_crud.crud import DBClient
from ff_crud import __config as connection_config
from utilities.logging_functions import echo_log
from utilities.general_utilities import _to_mysql_datetime


def handle_ringcentral_payload(
    payload: dict,
) -> Tuple[RingCentralSession, RingCentralNotification]:
    """
    Converts a raw RingCentral webhook payload into
    RingCentralSession and RingCentralNotification models.
    """

    try:

        log_file = "websockets.websocket_tools.handle_ringcentral_payload.py"

        body = payload.get("body", {}) or {}
        parties = body.get("parties", []) or []
        main_party = parties[0] if parties else {}

        from_info = main_party.get("from", {}) or {}
        to_info = main_party.get("to", {}) or {}
        status = main_party.get("status", {}) or {}

        db_client = DBClient(connection_config.firefly_dev)
        ring_central_methods = RingCentralMethods(db_client)

        # Normalize datetimes
        event_time_dt = _to_mysql_datetime(body.get("eventTime"))
        rc_timestamp_dt = _to_mysql_datetime(payload.get("timestamp"))

        # --- Build session object ---
        session: RingCentralSession = {
            "telephony_session_id": body.get("telephonySessionId"),
            "session_id": body.get("sessionId"),
            "account_id": (
                int(main_party.get("accountId"))
                if main_party.get("accountId")
                else None
            ),
            "direction": main_party.get("direction"),
            "server_id": body.get("serverId"),
            "from_name": from_info.get("name"),
            "from_phone": from_info.get("phoneNumber"),
            "from_extension": from_info.get("extensionId"),
            "to_name": to_info.get("name"),
            "to_phone": to_info.get("phoneNumber"),
            "to_extension": to_info.get("extensionId"),
            "started_at": event_time_dt,
            "last_updated_at": event_time_dt,
            "department_id": None,  # linked later
        }

        # --- Build notification object ---
        notification: RingCentralNotification = {
            "telephony_session_id": body.get("telephonySessionId"),
            "uuid": payload.get("uuid"),
            "event_path": payload.get("event"),
            "rc_timestamp": rc_timestamp_dt,
            "subscription_id": payload.get("subscriptionId"),
            "owner_id": int(payload.get("ownerId")) if payload.get("ownerId") else None,
            "event_time": event_time_dt,
            "sequence": body.get("sequence"),
            "server_id": body.get("serverId"),
            "session_id": body.get("sessionId"),
            "direction": main_party.get("direction"),
            "status_code": status.get("code"),
            "rcc": status.get("rcc"),
            "missed_call": main_party.get("missedCall"),
            "muted": main_party.get("muted"),
            "stand_alone": main_party.get("standAlone"),
            "from_name": from_info.get("name"),
            "from_phone": from_info.get("phoneNumber"),
            "from_extension": from_info.get("extensionId"),
            "to_name": to_info.get("name"),
            "to_phone": to_info.get("phoneNumber"),
            "to_extension": to_info.get("extensionId"),
            "raw_payload": payload,
        }

        # Determine customer phone depending on call direction
        notification_customer_phone = (
            notification.get("from_phone")
            if session.get("direction") == "Inbound"
            else notification.get("to_phone")
        )

        if not notification_customer_phone:
            echo_log(
                "No customer phone number found in notification payload; skipping customer lookup and call action creation.",
                log_file,
            )
            notification_customer_phone = ""

        # ----- TEST DIFFERENT PHONE FORMATS TO FIND CUSTOMER ID -----
        customer_id = None
        if notification_customer_phone:
            # Basic normalization attempts based on length
            phone_ten_digit = (
                notification_customer_phone[2:12]
                if len(notification_customer_phone) == 12
                else (
                    notification_customer_phone[1:12]
                    if len(notification_customer_phone) == 11
                    else notification_customer_phone
                )
            )
            phone_eleven_digit = (
                notification_customer_phone[1:12]
                if len(notification_customer_phone) == 12
                else (
                    "1" + notification_customer_phone
                    if len(notification_customer_phone) == 10
                    else notification_customer_phone
                )
            )
            phone_twelve_digit = (
                "+1" + notification_customer_phone
                if len(notification_customer_phone) == 10
                else (
                    "+" + notification_customer_phone
                    if len(notification_customer_phone) == 11
                    else notification_customer_phone
                )
            )

            echo_log(
                f"Testing phone: {notification_customer_phone}, ten_digit: {phone_ten_digit}, eleven_digit: {phone_eleven_digit}, twelve_digit: {phone_twelve_digit}",
                log_file,
            )

            # Try each format until found (DO NOT overwrite later)
            for candidate in (
                phone_ten_digit,
                phone_eleven_digit,
                phone_twelve_digit,
                notification_customer_phone,
            ):
                if not candidate:
                    continue
                cid = ring_central_methods.get_customer_id_by_phone(
                    phone_number=candidate
                )
                if cid:
                    customer_id = cid
                    break

        is_existing_session: bool = ring_central_methods.validate_existing_session(
            telephony_session_id=session["telephony_session_id"]
        )
        echo_log(f"Is existing session: {is_existing_session}", log_file)

        department_ops = DepartmentOperations(db_client)

        extension_id = (
            main_party.get("extensionId")
            or to_info.get("extensionId")
            or from_info.get("extensionId")
        )

        echo_log(
            f"[DeptLink] extension_id candidates -> main_party={main_party.get('extensionId')}, "
            f"to={to_info.get('extensionId')}, from={from_info.get('extensionId')} | chosen={extension_id}",
            log_file,
        )

        department = None
        department_id = None

        if extension_id:
            try:
                department = department_ops.get_department_by_extension_id(
                    extension_id=extension_id
                )
                department_id = department.get("id") if department else None
                echo_log(
                    f"[DeptLink] lookup result -> department={department} | department_id={department_id}",
                    log_file,
                )
            except Exception as e:
                echo_log(
                    f"[DeptLink] ERROR looking up department for extension_id={extension_id}: {e}",
                    log_file,
                )
        else:
            echo_log(
                "[DeptLink] No extension_id found in payload; cannot link department.",
                log_file,
            )

        session["department_id"] = department_id

        echo_log(
            f"Linked session to department_id: {department_id} using extension_id: {extension_id}",
            log_file,
        )

        # Treat voicemail as a missed-call action too
        is_voicemail = (
            notification.get("status_code") == "Voicemail"
            or payload.get("body", {})
            .get("parties", [{}])[0]
            .get("status", {})
            .get("reason")
            == "Voicemail"
        )
        should_create_call_action = (
            notification.get("missed_call") is True
        ) or is_voicemail

        echo_log(
            f"Should create call action: {should_create_call_action} (missed_call: {notification.get('missed_call')}, is_voicemail: {is_voicemail})",
            log_file,
        )

        if should_create_call_action and department_id:
            action_label = "voicemail" if is_voicemail else "missed call"

            echo_log(
                f"Handling {action_label} for session: {session['telephony_session_id']}",
                log_file,
            )

            occurred_at_iso = body.get("eventTime") or payload.get("timestamp")

            call_action_ops = CallActionOperations(db_client=db_client)

            # If you want to store voicemail as its own action type, switch this line:
            action_type = (
                CallActionType.VOICEMAIL if is_voicemail else CallActionType.MISSED
            )

            call_action_input: CreateCallActionInput = {
                "action_type": action_type,
                "status": CallActionStatus.OPEN,
                "priority": CallActionPriority.NORMAL,
                "telephony_session_id": session["telephony_session_id"],
                "department_id": department_id,
                "customer_id": customer_id,
                "phone_number": notification_customer_phone or None,
                "summary": (
                    f"Voicemail from {notification_customer_phone}"
                    if (is_voicemail and notification_customer_phone)
                    else (
                        f"Missed call from {notification_customer_phone}"
                        if notification_customer_phone
                        else ("Voicemail" if is_voicemail else "Missed call")
                    )
                ),
                "occurred_at": occurred_at_iso,
                "assigned_user_id": None,
            }

            call_action_id = call_action_ops.create_call_action(call_action_input)

            if call_action_id:
                echo_log(
                    f"Created call action ({action_label}) with ID: {call_action_id} for session: {session['telephony_session_id']}",
                    log_file,
                )
            else:
                echo_log(
                    f"Failed to create call action ({action_label}) for session: {session['telephony_session_id']}",
                    log_file,
                )

        # Create new session in DB
        if not is_existing_session:
            session_id = ring_central_methods.create_session(
                session=session, customer_id=customer_id
            )
        else:
            session_id = None

        notification_id = ring_central_methods.create_notification(
            notification=notification
        )

        if session_id:
            echo_log(f"RingCentral session created with ID: {session_id}", log_file)
        elif is_existing_session and not session_id:
            echo_log(
                "RingCentral session already exists. No new session created.", log_file
            )
        else:
            echo_log("Failed to create RingCentral session.", log_file)

        if notification_id:
            echo_log(
                f"RingCentral notification created with ID: {notification_id}", log_file
            )
        else:
            echo_log("Failed to create RingCentral notification.", log_file)

        echo_log(
            f"Completed handling RingCentral payload for telephony_session_id: {session['telephony_session_id']}",
            log_file,
        )

        return session, notification
    except Exception as e:
        echo_log(
            f"Error in handle_ringcentral_payload: {e}",
            "websockets.websocket_tools.handle_ringcentral_payload.py",
        )
