"""Premium subscription routes.

Thin request handlers attached to ``premium_bp``. Student-facing routes cover
the premium overview, the manual activation request and its status/success page;
admin routes (guarded by ``admin_required``) provide the Super Admin review
console. All business logic lives in :mod:`app.premium.services`.
"""

from __future__ import annotations

from flask import current_app, flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required

from app.admin.utils import admin_required
from app.extensions import db
from app.models import PremiumFeature, PremiumPlan
from app.marketplace.services import (
    FeatureListingError,
    feature_listing as feature_listing_service,
    get_featurable_listing_cards,
    get_featured_listing,
    get_owned_listing_or_404,
)
from app.premium import config, premium_bp, services
from app.premium.analytics import get_premium_dashboard
from app.premium.forms import PremiumRequestForm
from app.premium.permissions import (
    can_send_unlimited_messages,
    can_view_without_ads,
    should_show_premium_badge,
)

# Communicated to students on the success/status page.
ESTIMATED_REVIEW_TIME = "within 24 hours"

# Premium expiry within this many days triggers the renewal reminder.
EXPIRY_REMINDER_DAYS = 7


def _discovery_benefits(user, has_featured: bool) -> list[dict]:
    """Active-benefit checklist for the dashboard. Each status is resolved from
    the existing capability helpers — no new entitlement logic."""
    return [
        {"title": "Premium Seller Badge", "icon": "bi-patch-check-fill",
         "status": "active" if should_show_premium_badge(user) else "inactive"},
        {"title": "Discovery Boost", "icon": "bi-rocket-takeoff-fill",
         "status": "active" if has_featured else "needs_action",
         "note": None if has_featured else "Feature a listing to boost its reach."},
        {"title": "Featured Listing", "icon": "bi-stars",
         "status": "active" if has_featured else "needs_action",
         "note": None if has_featured else "No listing selected."},
        {"title": "Seller Analytics", "icon": "bi-graph-up-arrow", "status": "active"},
        {"title": "Ad-Free Browsing", "icon": "bi-badge-ad-fill",
         "status": "active" if can_view_without_ads(user) else "inactive"},
        {"title": "Unlimited Messaging", "icon": "bi-chat-dots-fill",
         "status": "active" if can_send_unlimited_messages(user) else "inactive"},
    ]


@premium_bp.route("/")
@login_required
def index():
    """Premium hub: a member dashboard when Premium is active, otherwise the
    pricing / purchase experience. All figures reuse existing services."""
    # Transparently retire any lapsed subscriptions on access (no scheduled job).
    services.cleanup_expired_premium_users()
    active_subscription = services.get_active_subscription(current_user)
    pending_request = services.get_pending_request(current_user)
    # Surface a recent rejected / more-info outcome so the student sees the reason.
    latest_request = None if (active_subscription or pending_request) else services.get_latest_request(current_user)
    if latest_request and latest_request.status.value not in ("rejected", "more_info"):
        latest_request = None

    dashboard = benefits = None
    days_left = 0
    if active_subscription is not None:
        # One reuse of the existing analytics service powers the whole dashboard
        # (featured card + analytics preview) — no duplicated queries.
        dashboard = get_premium_dashboard(current_user)
        benefits = _discovery_benefits(current_user, dashboard["featured"] is not None)
        days_left = services.premium_days_remaining(current_user)

    return render_template(
        "premium/index.html",
        plans=config.get_plans(enabled_only=True),
        features=config.get_features(enabled_only=True),
        payment_settings=config.get_payment_settings(),
        payment_methods=config.get_enabled_payment_methods(),
        currency=config.CURRENCY_SYMBOL,
        active_subscription=active_subscription,
        pending_request=pending_request,
        latest_request=latest_request,
        dashboard=dashboard,
        benefits=benefits,
        days_left=days_left,
        expiry_soon=(0 < days_left <= EXPIRY_REMINDER_DAYS),
    )


@premium_bp.route("/feature-listing")
@login_required
def feature_listing():
    """Choose which of the member's listings to feature (Premium only)."""
    services.cleanup_expired_premium_users()
    if not services.is_user_currently_premium(current_user):
        flash("Featuring listings is a Premium feature. Upgrade to unlock it.", "info")
        return redirect(url_for("premium.index"))
    return render_template(
        "premium/feature_listing.html",
        listings=get_featurable_listing_cards(current_user),
        current_featured=get_featured_listing(current_user),
    )


@premium_bp.route("/feature-listing/<public_id>", methods=["POST"])
@login_required
def set_featured(public_id: str):
    """Feature one of the member's listings (reuses the marketplace service —
    no new business logic)."""
    if not services.is_user_currently_premium(current_user):
        flash("Featuring listings is a Premium feature. Upgrade to unlock it.", "info")
        return redirect(url_for("premium.index"))
    listing = get_owned_listing_or_404(public_id, current_user)
    try:
        replaced = feature_listing_service(listing, current_user)
    except FeatureListingError as exc:
        flash(str(exc), "warning")
    else:
        if replaced is not None:
            flash(f"⭐ “{listing.title}” is now featured — it replaced your previous featured listing.", "success")
        else:
            flash(f"⭐ “{listing.title}” is now featured.", "success")
    return redirect(url_for("premium.index"))


@premium_bp.route("/analytics")
@login_required
def analytics():
    """Premium-only analytics dashboard. All figures are computed in the service
    layer; the template just renders the returned dictionary."""
    services.cleanup_expired_premium_users()
    if not services.is_user_currently_premium(current_user):
        flash("Premium Analytics is available to Premium members. Upgrade to unlock insights.", "info")
        return redirect(url_for("premium.index"))
    return render_template(
        "premium/analytics.html",
        dashboard=get_premium_dashboard(current_user),
        currency=services.CURRENCY_SYMBOL,
    )


@premium_bp.route("/request", methods=["GET", "POST"])
@login_required
def request_premium():
    """Submit a manual premium activation request."""
    if services.get_active_subscription(current_user):
        flash("You already have an active Premium subscription.", "info")
        return redirect(url_for("premium.index"))
    # An open request exists — show the friendly "under review" status page.
    if services.get_pending_request(current_user):
        return redirect(url_for("premium.request_success"))

    plans = config.get_plans(enabled_only=True)
    payment_methods = config.get_enabled_payment_methods()
    form = PremiumRequestForm()
    # Choices come from the admin-configured plans / enabled payment methods.
    form.plan_name.choices = [(p.name, p.name) for p in plans]
    form.payment_method.choices = payment_methods

    if form.validate_on_submit():
        try:
            receipt_path = services.save_premium_receipt(form.receipt.data)
        except ValueError as exc:
            flash(str(exc), "warning")
            receipt_path = None
        try:
            services.create_premium_request(
                current_user,
                plan_name=form.plan_name.data,
                payment_method=form.payment_method.data,
                transaction_reference=form.transaction_reference.data,
                remarks=form.remarks.data,
                receipt_path=receipt_path,
            )
        except services.DuplicateRequestError:
            return redirect(url_for("premium.request_success"))
        except services.PremiumError as exc:
            flash(str(exc), "danger")
        else:
            return redirect(url_for("premium.request_success", new=1))

    return render_template(
        "premium/request.html",
        form=form,
        plans=plans,
        payment_settings=config.get_payment_settings(),
        payment_methods=payment_methods,
        upi_qr=config.payment_qr_src(),
        upi_uri=config.upi_payment_uri(),
        currency=config.CURRENCY_SYMBOL,
    )


@premium_bp.route("/request/success")
@login_required
def request_success():
    """Request status page (timeline) for the user's latest request of any
    status — submitted / awaiting verification / approved / rejected / more info."""
    latest = services.get_latest_request(current_user)
    if latest is None:
        return redirect(url_for("premium.index"))
    return render_template(
        "premium/request_success.html",
        req=latest,
        just_submitted=request.args.get("new") == "1",
        plan=config.get_plan_by_name(latest.plan_name),
        currency=config.CURRENCY_SYMBOL,
        estimated_time=ESTIMATED_REVIEW_TIME,
    )


@premium_bp.route("/request/receipt/<int:request_id>")
@login_required
def request_receipt(request_id: int):
    """Serve a request's receipt image to its owner (or a Super Admin) only."""
    from flask import abort, send_from_directory
    from app.models import PremiumRequest
    req = db.session.get(PremiumRequest, request_id)
    if req is None or not req.receipt_path:
        abort(404)
    is_admin = getattr(current_user, "role", None) and current_user.role.value == "super_admin"
    if req.user_id != current_user.id and not is_admin:
        abort(404)
    return send_from_directory(current_app.config["PREMIUM_RECEIPT_FOLDER"], req.receipt_path)


# --- Admin Premium Management (configuration) ------------------------------

@premium_bp.route("/admin/settings")
@login_required
@admin_required
def admin_settings():
    """Premium Management hub: payment settings, plans and features (all editable)."""
    return render_template(
        "premium/admin_settings.html",
        payment_settings=config.get_payment_settings(),
        plans=config.get_plans(),
        features=config.get_features(enabled_only=False),
        qr_src=config.payment_qr_src(),
        qr_uploaded=config.uploaded_qr_url(),
        currency=config.CURRENCY_SYMBOL,
    )


@premium_bp.route("/admin/settings/payment", methods=["POST"])
@login_required
@admin_required
def admin_update_payment():
    form = request.form
    config.update_payment_settings(
        active_upi_id=form.get("active_upi_id"),
        bank_name=form.get("bank_name"),
        account_holder=form.get("account_holder"),
        account_number=form.get("account_number"),
        ifsc=form.get("ifsc"),
        cash_instructions=form.get("cash_instructions"),
        support_email=form.get("support_email"),
        support_phone=form.get("support_phone"),
        enable_upi=form.get("enable_upi") in ("1", "on", "true"),
        enable_bank=form.get("enable_bank") in ("1", "on", "true"),
        enable_cash=form.get("enable_cash") in ("1", "on", "true"),
    )
    flash("Payment settings updated.", "success")
    return redirect(url_for("premium.admin_settings"))


@premium_bp.route("/admin/settings/qr", methods=["POST"])
@login_required
@admin_required
def admin_update_qr():
    """Upload/replace or remove the admin-configured UPI QR image.

    Reuses the shared image validation + public-static storage helpers (no new
    upload system). The change is live immediately — no restart.
    """
    action = (request.form.get("action") or "upload").strip()
    if action == "remove":
        config.clear_payment_qr()
        flash("UPI QR code removed — the generated QR will be used.", "info")
    else:
        try:
            config.set_payment_qr(request.files.get("qr_image"))
        except ValueError as exc:
            flash(str(exc), "warning")
        else:
            flash("UPI QR code updated.", "success")
    return redirect(url_for("premium.admin_settings"))


@premium_bp.route("/admin/settings/plans", methods=["POST"])
@login_required
@admin_required
def admin_save_plan():
    form = request.form
    plan_id = form.get("plan_id", type=int)
    fields = {
        "name": form.get("name"),
        "duration_days": form.get("duration_days", type=int) or 30,
        "price": form.get("price", type=float) or 0,
        "description": form.get("description"),
        "sort_order": form.get("sort_order", type=int) or 0,
        "enabled": form.get("enabled") in ("1", "on", "true"),
    }
    if plan_id:
        plan = db.session.get(PremiumPlan, plan_id)
        if plan:
            config.update_plan(plan, **fields)
            flash("Plan updated.", "success")
    elif fields["name"]:
        config.create_plan(**fields)
        flash("Plan created.", "success")
    return redirect(url_for("premium.admin_settings"))


@premium_bp.route("/admin/settings/features", methods=["POST"])
@login_required
@admin_required
def admin_save_feature():
    form = request.form
    feature_id = form.get("feature_id", type=int)
    fields = {
        "title": form.get("title"),
        "description": form.get("description"),
        "icon": form.get("icon"),
        "display_order": form.get("display_order", type=int) or 0,
        "enabled": form.get("enabled") in ("1", "on", "true"),
    }
    if feature_id:
        feature = db.session.get(PremiumFeature, feature_id)
        if feature:
            config.update_feature(feature, **fields)
            flash("Feature updated.", "success")
    elif fields["title"]:
        config.create_feature(**fields)
        flash("Feature created.", "success")
    return redirect(url_for("premium.admin_settings"))


# --- Admin review console --------------------------------------------------

@premium_bp.route("/admin/requests")
@login_required
@admin_required
def admin_requests():
    """List every premium request with approve/reject actions."""
    requests = services.list_premium_requests()
    return render_template(
        "premium/admin_requests.html",
        requests=requests,
        currency=config.CURRENCY_SYMBOL,
        plans=config.plan_lookup(),
    )


@premium_bp.route("/admin/requests/<public_id>")
@login_required
@admin_required
def admin_request_detail(public_id: str):
    """Full detail for a single premium request, with approve/reject actions."""
    req = services.get_request_or_404(public_id)
    return render_template(
        "premium/admin_request_detail.html",
        req=req,
        plans=config.plan_lookup(),
        currency=config.CURRENCY_SYMBOL,
    )


@premium_bp.route("/admin/requests/<public_id>/approve", methods=["POST"])
@login_required
@admin_required
def approve_request(public_id: str):
    req = services.get_request_or_404(public_id)
    try:
        subscription = services.approve_premium_request(req, current_user)
    except services.RequestNotPendingError as exc:
        flash(str(exc), "warning")
    except services.PremiumError as exc:
        flash(str(exc), "danger")
    else:
        name = (
            req.user.profile.full_name
            if req.user and req.user.profile
            else (req.user.email if req.user else "the user")
        )
        flash(
            f"Approved — Premium activated for {name} until "
            f"{subscription.end_date.strftime('%d %b %Y')}.",
            "success",
        )
    return redirect(url_for("premium.admin_requests"))


@premium_bp.route("/admin/requests/<public_id>/reject", methods=["POST"])
@login_required
@admin_required
def reject_request(public_id: str):
    req = services.get_request_or_404(public_id)
    reason = (request.form.get("reason") or "").strip()
    if not reason:
        flash("Please provide a reason for rejecting the request.", "warning")
        return redirect(url_for("premium.admin_request_detail", public_id=public_id))
    try:
        services.reject_premium_request(req, current_user, reason=reason)
    except services.RequestNotPendingError as exc:
        flash(str(exc), "warning")
    else:
        flash("Request rejected. The student has been notified.", "info")
    return redirect(url_for("premium.admin_requests"))


@premium_bp.route("/admin/requests/<public_id>/more-info", methods=["POST"])
@login_required
@admin_required
def more_info_request(public_id: str):
    """Ask the student for more information (they can then resubmit)."""
    req = services.get_request_or_404(public_id)
    message = (request.form.get("message") or "").strip()
    if not message:
        flash("Please describe what information is needed.", "warning")
        return redirect(url_for("premium.admin_request_detail", public_id=public_id))
    try:
        services.request_more_info(req, current_user, message)
    except services.RequestNotPendingError as exc:
        flash(str(exc), "warning")
    else:
        flash("Requested more information. The student has been notified.", "info")
    return redirect(url_for("premium.admin_requests"))
