# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Messaging Skill

Unified messaging across iMessage, WhatsApp, Signal, and SMS.
The agent can intelligently pick the best platform or use a specific one.
"""

import logging
import os
import platform

logger = logging.getLogger(__name__)


def detect_available_platforms() -> list:
    """Detect which messaging platforms are available."""
    available = []

    # Check iMessage (macOS only)
    if platform.system() == "Darwin":
        from pathlib import Path

        if (Path.home() / "Library" / "Messages" / "chat.db").exists():
            available.append("imessage")

    # Check WhatsApp bridge
    try:
        import socket

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        result = sock.connect_ex(("localhost", 3001))
        sock.close()
        if result == 0:
            available.append("whatsapp")
    except (socket.error, OSError):
        pass

    # Check Signal
    try:
        import subprocess

        result = subprocess.run(["signal-cli", "--version"], capture_output=True, timeout=2)
        if result.returncode == 0 and os.environ.get("SIGNAL_PHONE"):
            available.append("signal")
    except (subprocess.SubprocessError, FileNotFoundError, OSError):
        pass

    # Check Twilio (SMS)
    if os.environ.get("TWILIO_ACCOUNT_SID") and os.environ.get("TWILIO_AUTH_TOKEN"):
        available.append("sms")

    # Check Matrix
    if os.environ.get("MATRIX_HOMESERVER") and os.environ.get("MATRIX_USER"):
        try:
            import importlib.util

            if importlib.util.find_spec("nio") is not None:
                available.append("matrix")
        except (ModuleNotFoundError, ValueError):
            pass

    return available


def send_message(data: dict) -> str:
    """
    Send a message using the best available platform.

    The platform can be specified, or auto-selected based on:
    - Contact's preferred platform (if known)
    - Available platforms
    - Message type/urgency
    """
    to = data.get("to", "")
    message = data.get("message", "")
    platform_pref = data.get("platform", "").lower()

    if not data.get("_confirmed"):
        from familiar.core.confirmations import needs_confirmation

        return needs_confirmation(
            tool_name="send_message",
            tool_input=data,
            preview=f"Send message to {to}: {message[:60]}...",
            risk="medium",
        )

    if not to or not message:
        return "Please provide 'to' and 'message'"

    available = detect_available_platforms()

    if not available:
        return (
            "❌ No messaging platforms available. Configure iMessage, WhatsApp, Signal, or Twilio."
        )

    # If platform specified, use it
    if platform_pref:
        if platform_pref not in available:
            return f"❌ {platform_pref} not available. Available: {', '.join(available)}"

        return _send_via_platform(platform_pref, to, message)

    # Auto-select platform
    # Priority: iMessage > WhatsApp > Signal > SMS

    # Check if it's an email (iMessage can send to emails)
    if "@" in to and "imessage" in available:
        return _send_via_platform("imessage", to, message)

    # Check if it's a phone number
    if "imessage" in available:
        return _send_via_platform("imessage", to, message)

    if "whatsapp" in available:
        return _send_via_platform("whatsapp", to, message)

    if "signal" in available:
        return _send_via_platform("signal", to, message)

    if "sms" in available:
        return _send_via_platform("sms", to, message)

    return "❌ Could not send message"


def _send_via_platform(platform_name: str, to: str, message: str) -> str:
    """Send via specific platform."""

    if platform_name == "imessage":
        try:
            from familiar.channels.imessage import send_imessage

            return send_imessage({"to": to, "message": message})
        except Exception as e:
            return f"❌ iMessage error: {e}"

    elif platform_name == "whatsapp":
        try:
            from familiar.channels.whatsapp import send_whatsapp

            return send_whatsapp({"to": to, "message": message})
        except Exception as e:
            return f"❌ WhatsApp error: {e}"

    elif platform_name == "signal":
        try:
            from familiar.channels.signal import send_signal

            return send_signal({"to": to, "message": message})
        except Exception as e:
            return f"❌ Signal error: {e}"

    elif platform_name == "sms":
        try:
            # Import from skills
            import sys
            from pathlib import Path

            sys.path.insert(0, str(Path(__file__).parent.parent / "sms"))
            from skill import send_sms

            return send_sms({"to": to, "message": message})
        except Exception as e:
            return f"❌ SMS error: {e}"

    elif platform_name == "matrix":
        try:
            from familiar.channels.matrix import send_matrix

            return send_matrix({"to": to, "message": message})
        except Exception as e:
            return f"❌ Matrix error: {e}"

    return f"❌ Unknown platform: {platform_name}"


def send_imessage(data: dict) -> str:
    """Send an iMessage."""
    to = data.get("to", "")
    message = data.get("message", "")

    if not data.get("_confirmed"):
        from familiar.core.confirmations import needs_confirmation

        return needs_confirmation(
            tool_name="send_imessage",
            tool_input=data,
            preview=f"Send message to {to}: {message[:60]}...",
            risk="medium",
        )

    try:
        from familiar.channels.imessage import send_imessage as _send

        return _send(data)
    except ImportError:
        return "❌ iMessage channel not available"
    except Exception as e:
        return f"❌ iMessage error: {e}"


def send_whatsapp(data: dict) -> str:
    """Send a WhatsApp message."""
    to = data.get("to", "")
    message = data.get("message", "")

    if not data.get("_confirmed"):
        from familiar.core.confirmations import needs_confirmation

        return needs_confirmation(
            tool_name="send_whatsapp",
            tool_input=data,
            preview=f"Send message to {to}: {message[:60]}...",
            risk="medium",
        )

    try:
        from familiar.channels.whatsapp import send_whatsapp as _send

        return _send(data)
    except ImportError:
        return "❌ WhatsApp channel not available"
    except Exception as e:
        return f"❌ WhatsApp error: {e}"


def send_signal_msg(data: dict) -> str:
    """Send a Signal message."""
    to = data.get("to", "")
    message = data.get("message", "")

    if not data.get("_confirmed"):
        from familiar.core.confirmations import needs_confirmation

        return needs_confirmation(
            tool_name="send_signal",
            tool_input=data,
            preview=f"Send message to {to}: {message[:60]}...",
            risk="medium",
        )

    try:
        from familiar.channels.signal import send_signal as _send

        return _send(data)
    except ImportError:
        return "❌ Signal channel not available"
    except Exception as e:
        return f"❌ Signal error: {e}"


def send_matrix_msg(data: dict) -> str:
    """Send a Matrix message."""
    to = data.get("to", "")
    message = data.get("message", "")

    if not data.get("_confirmed"):
        from familiar.core.confirmations import needs_confirmation

        return needs_confirmation(
            tool_name="send_matrix",
            tool_input=data,
            preview=f"Send message to {to}: {message[:60]}...",
            risk="medium",
        )

    try:
        from familiar.channels.matrix import send_matrix as _send

        return _send(data)
    except ImportError:
        from familiar.core.deps import MATRIX_PACKAGES, ensure_packages

        ok, _ = ensure_packages(MATRIX_PACKAGES)
        if ok:
            try:
                from familiar.channels.matrix import send_matrix as _send

                return _send(data)
            except Exception as e2:
                return f"❌ Matrix send failed after install: {e2}"
        return "❌ Matrix channel not available. Check server logs."
    except Exception as e:
        return f"❌ Matrix error: {e}"


def check_platforms(data: dict) -> str:
    """Check which messaging platforms are available."""
    available = detect_available_platforms()

    if not available:
        return "❌ No messaging platforms configured"

    lines = ["📱 Available messaging platforms:\n"]

    platform_info = {
        "imessage": "iMessage (macOS Messages app)",
        "whatsapp": "WhatsApp (via bridge)",
        "signal": "Signal (via signal-cli)",
        "sms": "SMS (via Twilio)",
        "matrix": "Matrix (via matrix-nio)",
    }

    for p in available:
        lines.append(f"  ✅ {platform_info.get(p, p)}")

    # Show unavailable ones
    all_platforms = ["imessage", "whatsapp", "signal", "sms", "matrix"]
    unavailable = [p for p in all_platforms if p not in available]

    if unavailable:
        lines.append("\n  Not configured:")
        for p in unavailable:
            lines.append(f"  ❌ {platform_info.get(p, p)}")

    return "\n".join(lines)


# Tool definitions
TOOLS = [
    {
        "name": "send_message",
        "description": (
            "Send a message using the best available platform."
            " Auto-selects from iMessage, WhatsApp, Signal, Matrix, or SMS."
            " Use when the user says 'message someone' without specifying a platform."
            " Returns delivery confirmation with platform used and message ID."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "to": {
                    "type": "string",
                    "description": "Recipient phone number, email, or Matrix ID",
                },
                "message": {"type": "string", "description": "Message to send"},
                "platform": {
                    "type": "string",
                    "description": "Optional: specific platform (imessage, whatsapp, signal, sms, matrix)",
                    "enum": ["imessage", "whatsapp", "signal", "sms", "matrix"],
                },
            },
            "required": ["to", "message"],
        },
        "handler": send_message,
        "requires_confirmation": True,
        "category": "messaging",
    },
    {
        "name": "send_imessage",
        "description": (
            "Send an iMessage via the macOS Messages app."
            " Use only when user explicitly requests iMessage."
            " Requires macOS with Messages configured; unavailable on Linux."
            " Returns delivery confirmation or error details."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "to": {"type": "string", "description": "Phone number or email"},
                "message": {"type": "string", "description": "Message text to send"},
            },
            "required": ["to", "message"],
        },
        "handler": send_imessage,
        "requires_confirmation": True,
        "category": "messaging",
    },
    {
        "name": "send_whatsapp",
        "description": (
            "Send a WhatsApp message via the WhatsApp bridge."
            " Use when user explicitly requests WhatsApp delivery."
            " Requires a running WhatsApp bridge on localhost:3001."
            " Returns delivery confirmation or bridge connection error."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "to": {"type": "string", "description": "Phone number with country code"},
                "message": {"type": "string", "description": "Message text to send"},
            },
            "required": ["to", "message"],
        },
        "handler": send_whatsapp,
        "requires_confirmation": True,
        "category": "messaging",
    },
    {
        "name": "send_signal",
        "description": (
            "Send a Signal message via signal-cli."
            " Use when user explicitly requests Signal delivery."
            " Requires signal-cli installed and SIGNAL_PHONE env var set."
            " Returns delivery confirmation or Signal CLI error."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "to": {"type": "string", "description": "Phone number with country code"},
                "message": {"type": "string", "description": "Message text to send"},
            },
            "required": ["to", "message"],
        },
        "handler": send_signal_msg,
        "requires_confirmation": True,
        "category": "messaging",
    },
    {
        "name": "send_matrix",
        "description": (
            "Send a Matrix message via matrix-nio."
            " Use when user explicitly requests Matrix delivery."
            " Requires MATRIX_HOMESERVER and MATRIX_USER env vars plus matrix-nio."
            " Returns delivery confirmation or connection error."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "to": {
                    "type": "string",
                    "description": "Matrix user ID (@user:server) or room ID (!room:server)",
                },
                "message": {"type": "string", "description": "Message text to send"},
            },
            "required": ["to", "message"],
        },
        "handler": send_matrix_msg,
        "requires_confirmation": True,
        "category": "messaging",
    },
    {
        "name": "check_messaging_platforms",
        "description": (
            "Check which messaging platforms are currently available."
            " Use to discover configured platforms before sending messages."
            " Read-only: does not modify any configuration or send messages."
            " Returns list of available and unavailable platforms."
        ),
        "input_schema": {"type": "object", "properties": {}},
        "handler": check_platforms,
        "category": "messaging",
    },
]
