"""Negotiation routes.

Thin request handlers that delegate to the service layer.
"""

from __future__ import annotations

from flask import flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required

from app.chat.services import get_conversation_for_user_or_404
from app.negotiation import negotiation_bp
from app.negotiation.forms import OfferForm
from app.negotiation.services import (
    InvalidOfferError,
    NegotiationError,
    OfferCreationError,
    accept_offer as accept_offer_service,
    counter_offer as counter_offer_service,
    create_offer as create_offer_service,
    get_offer_for_conversation_or_404,
    reject_offer as reject_offer_service,
)


@negotiation_bp.route("/listings/<listing_public_id>/start")
@login_required
def start_negotiation(listing_public_id: str):
    """Open (or create) the conversation for a listing, then go to negotiation.

    Mirrors the lazy-creation behaviour of starting a chat: the conversation is
    created on the buyer's first deliberate action so the negotiation page never
    has to be reached with a missing conversation.
    """
    from app.chat.services import SelfConversationError, get_or_create_conversation
    from app.marketplace.services import get_visible_listing_or_404

    listing = get_visible_listing_or_404(listing_public_id)
    try:
        conversation = get_or_create_conversation(current_user, listing)
    except SelfConversationError as exc:
        flash(str(exc), "warning")
        return redirect(url_for("marketplace.listing_detail", public_id=listing_public_id))
    return redirect(
        url_for("negotiation.conversation_negotiation", public_id=conversation.public_id)
    )


@negotiation_bp.route("/conversations/<public_id>/negotiation")
@login_required
def conversation_negotiation(public_id: str):
    conversation = get_conversation_for_user_or_404(public_id, current_user)
    other = (
        conversation.seller
        if conversation.buyer_id == current_user.id
        else conversation.buyer
    )
    return render_template(
        "chat/negotiation.html",
        conversation=conversation,
        listing=conversation.listing,
        other=other,
        offer_form=OfferForm(),
    )


@negotiation_bp.route("/<public_id>/offers", methods=["POST"])
@login_required
def create_offer(public_id: str):
    conversation = get_conversation_for_user_or_404(public_id, current_user)
    form = OfferForm(formdata=request.form)
    if form.validate():
        try:
            create_offer_service(conversation, current_user, form.amount.data, form.optional_message.data)
        except (InvalidOfferError, OfferCreationError, NegotiationError) as exc:
            flash(str(exc), "warning")
    else:
        for field_errors in form.errors.values():
            for error in field_errors:
                flash(error, "danger")
    return redirect(url_for("negotiation.conversation_negotiation", public_id=public_id))


@negotiation_bp.route("/<public_id>/offers/<offer_public_id>/accept", methods=["POST"])
@login_required
def accept_offer(public_id: str, offer_public_id: str):
    conversation = get_conversation_for_user_or_404(public_id, current_user)
    offer = get_offer_for_conversation_or_404(offer_public_id, conversation)
    try:
        accept_offer_service(offer, current_user)
    except (InvalidOfferError, OfferCreationError, NegotiationError) as exc:
        flash(str(exc), "warning")
    return redirect(url_for("negotiation.conversation_negotiation", public_id=public_id))


@negotiation_bp.route("/<public_id>/offers/<offer_public_id>/reject", methods=["POST"])
@login_required
def reject_offer(public_id: str, offer_public_id: str):
    conversation = get_conversation_for_user_or_404(public_id, current_user)
    offer = get_offer_for_conversation_or_404(offer_public_id, conversation)
    try:
        reject_offer_service(offer, current_user)
    except (InvalidOfferError, OfferCreationError, NegotiationError) as exc:
        flash(str(exc), "warning")
    return redirect(url_for("negotiation.conversation_negotiation", public_id=public_id))


@negotiation_bp.route("/<public_id>/offers/<offer_public_id>/counter", methods=["POST"])
@login_required
def counter_offer(public_id: str, offer_public_id: str):
    conversation = get_conversation_for_user_or_404(public_id, current_user)
    offer = get_offer_for_conversation_or_404(offer_public_id, conversation)
    form = OfferForm(formdata=request.form)
    if form.validate():
        try:
            counter_offer_service(offer, current_user, form.amount.data, form.optional_message.data)
        except (InvalidOfferError, OfferCreationError, NegotiationError) as exc:
            flash(str(exc), "warning")
    else:
        for field_errors in form.errors.values():
            for error in field_errors:
                flash(error, "danger")
    return redirect(url_for("negotiation.conversation_negotiation", public_id=public_id))
