from __future__ import annotations

from flask import flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required

from app.extensions import db
from app.models import Listing, Offer, RelatedEntityType
from app.notifications import notifications_bp
from app.notifications.services import (
    get_notification_or_404,
    get_user_notifications,
    mark_all_notifications_read,
    mark_notification_read,
)


@notifications_bp.route("/")
@login_required
def list_notifications() -> str:
    from app.moderation.services import MOD_NOTIFICATION_LINKS

    page = request.args.get("page", 1, type=int)
    pagination = get_user_notifications(current_user, page)
    return render_template(
        "notifications/list.html", pagination=pagination, mod_links=MOD_NOTIFICATION_LINKS
    )


@notifications_bp.route("/mark-all-read", methods=["POST"])
@login_required
def mark_all_read():
    """Mark every unread notification read (thin wrapper over the service)."""
    updated = mark_all_notifications_read(current_user)
    if updated:
        flash(f"Marked {updated} notification{'' if updated == 1 else 's'} as read.", "success")
    return redirect(url_for("notifications.list_notifications"))


@notifications_bp.route("/<public_id>")
@login_required
def open_notification(public_id: str):
    """Open a notification: mark it read and route to the record it concerns.

    Each related-entity type maps to its own destination. If the linked record
    is gone (or the user is no longer allowed to see it) the notification is
    still marked read and the user is returned to the list with a notice.
    """
    from app.chat.services import get_conversation_by_id_for_user_or_none

    notification = get_notification_or_404(public_id, current_user)
    entity_type = notification.related_entity_type
    entity_id = notification.related_entity_id

    def _dead_end(message: str):
        # Reading a stale notification should still clear it from "unread".
        mark_notification_read(notification, current_user)
        flash(message, "warning")
        return redirect(url_for("notifications.list_notifications"))

    if entity_type == RelatedEntityType.CONVERSATION:
        if entity_id is None:
            return _dead_end("This conversation is no longer available.")
        conversation = get_conversation_by_id_for_user_or_none(entity_id, current_user)
        if conversation is None:
            return _dead_end("This conversation is no longer available.")
        mark_notification_read(notification, current_user)
        return redirect(url_for("chat.thread", public_id=conversation.public_id))

    if entity_type == RelatedEntityType.OFFER:
        if entity_id is None:
            return _dead_end("This offer is no longer available.")
        offer = db.session.get(Offer, entity_id)
        # Only the offer's own buyer or seller may follow the link.
        if offer is None or current_user.id not in (offer.buyer_id, offer.seller_id):
            return _dead_end("This offer is no longer available.")
        conversation = offer.conversation
        if conversation is None:
            return _dead_end("This offer is no longer available.")
        mark_notification_read(notification, current_user)
        return redirect(
            url_for("negotiation.conversation_negotiation", public_id=conversation.public_id)
        )

    if entity_type == RelatedEntityType.LISTING:
        if entity_id is None:
            return _dead_end("This listing is no longer available.")
        listing = db.session.get(Listing, entity_id)
        if listing is None:
            return _dead_end("This listing is no longer available.")
        mark_notification_read(notification, current_user)
        return redirect(url_for("marketplace.listing_detail", public_id=listing.public_id))

    # Moderation notifications (reporter + reported-user) all link to the report;
    # the destination (My Reports / My Listings / Community Guidelines) is resolved
    # from the notification's title so each opens the most relevant page.
    if entity_type == RelatedEntityType.REPORT:
        from app.moderation.services import moderation_notification_link

        link = moderation_notification_link(notification)
        if link is None:
            return _dead_end("This notification cannot be opened yet.")
        mark_notification_read(notification, current_user)
        return redirect(url_for(link["endpoint"]))

    return _dead_end("This notification cannot be opened yet.")
