import logging
from datetime import datetime, timezone

from quart import Blueprint, request, jsonify

from blueprints.users.decorators import admin_required
from .models import ScheduledMessage, MessageChannel, MessageStatus, Recurrence

scheduled_messages_blueprint = Blueprint(
    "scheduled_messages_api", __name__, url_prefix="/api/scheduled-messages"
)

logger = logging.getLogger(__name__)


def _serialize(msg: ScheduledMessage) -> dict:
    return {
        "id": str(msg.id),
        "recipient": msg.recipient,
        "channel": msg.channel.value,
        "content": msg.content,
        "subject": msg.subject,
        "scheduled_at": msg.scheduled_at.isoformat(),
        "status": msg.status.value,
        "recurrence": msg.recurrence.value,
        "use_agent": msg.use_agent,
        "error_message": msg.error_message,
        "created_at": msg.created_at.isoformat(),
        "updated_at": msg.updated_at.isoformat(),
    }


@scheduled_messages_blueprint.route("/", methods=["GET"])
@admin_required
async def list_messages():
    messages = await ScheduledMessage.all().order_by("-scheduled_at")
    return jsonify([_serialize(m) for m in messages])


@scheduled_messages_blueprint.route("/", methods=["POST"])
@admin_required
async def create_message():
    data = await request.get_json()
    if not data:
        return jsonify({"error": "Invalid payload"}), 400

    recipient = (data.get("recipient") or "").strip()
    channel = data.get("channel")
    content = (data.get("content") or "").strip()
    subject = (data.get("subject") or "").strip() or None
    scheduled_at_str = data.get("scheduled_at")

    recurrence_str = data.get("recurrence", "none")

    if not recipient or not channel or not content or not scheduled_at_str:
        return jsonify(
            {"error": "recipient, channel, content, and scheduled_at are required"}
        ), 400

    try:
        channel_enum = MessageChannel(channel)
    except ValueError:
        return jsonify(
            {"error": f"Invalid channel: {channel}. Must be 'imessage' or 'email'"}
        ), 400

    try:
        recurrence_enum = Recurrence(recurrence_str)
    except ValueError:
        return jsonify(
            {
                "error": f"Invalid recurrence: {recurrence_str}. Must be 'none', 'daily', 'weekly', or 'monthly'"
            }
        ), 400

    if channel_enum == MessageChannel.EMAIL and not subject:
        return jsonify({"error": "subject is required for email messages"}), 400

    try:
        scheduled_at = datetime.fromisoformat(scheduled_at_str)
        if scheduled_at.tzinfo is None:
            scheduled_at = scheduled_at.replace(tzinfo=timezone.utc)
    except ValueError:
        return jsonify({"error": "Invalid scheduled_at format"}), 400

    if scheduled_at <= datetime.now(timezone.utc):
        return jsonify({"error": "scheduled_at must be in the future"}), 400

    from quart_jwt_extended import get_jwt_identity

    user_id = get_jwt_identity()

    use_agent = bool(data.get("use_agent", False))

    msg = await ScheduledMessage.create(
        recipient=recipient,
        channel=channel_enum,
        content=content,
        subject=subject,
        scheduled_at=scheduled_at,
        recurrence=recurrence_enum,
        use_agent=use_agent,
        created_by_id=user_id,
    )
    return jsonify(_serialize(msg)), 201


@scheduled_messages_blueprint.route("/<msg_id>", methods=["PUT"])
@admin_required
async def update_message(msg_id: str):
    msg = await ScheduledMessage.get_or_none(id=msg_id)
    if not msg:
        return jsonify({"error": "Not found"}), 404

    if msg.status != MessageStatus.PENDING:
        return jsonify({"error": "Can only update pending messages"}), 400

    data = await request.get_json()
    if not data:
        return jsonify({"error": "Invalid payload"}), 400

    if "recipient" in data:
        msg.recipient = data["recipient"].strip()
    if "channel" in data:
        try:
            msg.channel = MessageChannel(data["channel"])
        except ValueError:
            return jsonify({"error": f"Invalid channel: {data['channel']}"}), 400
    if "content" in data:
        msg.content = data["content"].strip()
    if "subject" in data:
        msg.subject = data["subject"].strip() or None
    if "recurrence" in data:
        try:
            msg.recurrence = Recurrence(data["recurrence"])
        except ValueError:
            return jsonify({"error": f"Invalid recurrence: {data['recurrence']}"}), 400
    if "use_agent" in data:
        msg.use_agent = bool(data["use_agent"])
    if "scheduled_at" in data:
        try:
            scheduled_at = datetime.fromisoformat(data["scheduled_at"])
            if scheduled_at.tzinfo is None:
                scheduled_at = scheduled_at.replace(tzinfo=timezone.utc)
            if scheduled_at <= datetime.now(timezone.utc):
                return jsonify({"error": "scheduled_at must be in the future"}), 400
            msg.scheduled_at = scheduled_at
        except ValueError:
            return jsonify({"error": "Invalid scheduled_at format"}), 400
    if "status" in data and data["status"] == "cancelled":
        msg.status = MessageStatus.CANCELLED

    if msg.channel == MessageChannel.EMAIL and not msg.subject:
        return jsonify({"error": "subject is required for email messages"}), 400

    await msg.save()
    return jsonify(_serialize(msg))


@scheduled_messages_blueprint.route("/<msg_id>", methods=["DELETE"])
@admin_required
async def delete_message(msg_id: str):
    msg = await ScheduledMessage.get_or_none(id=msg_id)
    if not msg:
        return jsonify({"error": "Not found"}), 404

    if msg.status not in (MessageStatus.PENDING, MessageStatus.CANCELLED):
        return jsonify({"error": "Can only delete pending or cancelled messages"}), 400

    await msg.delete()
    return jsonify({"status": "deleted"})
