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

from app.extensions import db
from app.models.customer import Customer, Purchase
from app.models.call import Call
from app.services.permissions import require, can_access
from app.services.activity_logger import log_action
from app.services import customer_service, tag_service, photo_storage
from app.services.jalali import jalali_str_to_gregorian_date, to_en_digits
from config import CUSTOMER_RATINGS

bp = Blueprint("customer_profile", __name__, url_prefix="/customers")

GENDER_FA = {"male": "آقا", "female": "خانم"}
STATUS_FA = dict(customer_service.STATUS_CHOICES)
RATING_ORDER = {"A+": 5, "A": 4, "B": 3, "C": 2, "D": 1}


@bp.route("/<int:customer_id>")
@login_required
@require("customer_profile")
def show(customer_id):
    customer = customer_service.get_customer_with_stats(customer_id)
    if not customer or customer.is_deleted:
        flash("مشتری یافت نشد", "error")
        return redirect(url_for("dashboard.index"))

    referrer = None
    if customer.referrer_customer_id:
        referrer = db.session.get(Customer, customer.referrer_customer_id)

    tags_grouped = tag_service.get_customer_tags_grouped(customer_id)
    calls = Call.query.filter_by(customer_id=customer_id).order_by(Call.call_date.desc()).all()

    log_action(current_user, "view", "customer", customer_id)

    return render_template(
        "customer_profile/show.html",
        customer=customer, referrer=referrer, tags_grouped=tags_grouped, calls=calls,
        gender_fa=GENDER_FA, status_fa=STATUS_FA, ratings=CUSTOMER_RATINGS,
        has_photo=photo_storage.photo_exists(customer.photo_path),
        all_tag_groups=tag_service.all_tags_grouped(),
        tag_service_current_ids=tag_service.get_customer_tag_ids(customer_id),
    )


@bp.route("/<int:customer_id>/rating", methods=["POST"])
@login_required
@require("customer_profile")
def set_rating(customer_id):
    customer = db.session.get(Customer, customer_id) or abort(404)
    rating = request.form.get("rating")
    if rating in CUSTOMER_RATINGS:
        customer.rating = rating
        customer.rating_is_manual = True
        db.session.commit()
        log_action(current_user, "update", "customer_rating", customer_id, {"rating": rating})
        flash(f"رتبه مشتری به {rating} تغییر کرد", "success")
    return redirect(url_for("customer_profile.show", customer_id=customer_id))


@bp.route("/<int:customer_id>/tags", methods=["POST"])
@login_required
@require("customer_profile")
def set_tags(customer_id):
    customer = db.session.get(Customer, customer_id) or abort(404)
    tag_ids = [int(v) for v in request.form.getlist("tag_ids") if v.isdigit()]
    tag_service.set_customer_tags(customer_id, tag_ids, assigned_by=current_user.id)
    log_action(current_user, "update", "customer_tags", customer_id)
    flash("تگ‌های مشتری به‌روزرسانی شد", "success")
    return redirect(url_for("customer_profile.show", customer_id=customer_id))


@bp.route("/<int:customer_id>/next-call-date", methods=["POST"])
@login_required
@require("customer_profile")
def set_next_call_date(customer_id):
    customer = db.session.get(Customer, customer_id) or abort(404)
    raw = "" if request.form.get("clear") else request.form.get("next_call_date", "").strip()
    if raw:
        try:
            customer.next_call_date = jalali_str_to_gregorian_date(raw)
        except Exception:
            flash("تاریخ وارد شده معتبر نیست", "error")
            return redirect(url_for("customer_profile.show", customer_id=customer_id))
    else:
        customer.next_call_date = None
    db.session.commit()
    log_action(current_user, "update", "customer_next_call_date", customer_id,
               {"next_call_date": raw or None})
    flash("تاریخ تماس بعدی ثبت شد" if raw else "تاریخ تماس بعدی پاک شد", "success")
    return redirect(url_for("customer_profile.show", customer_id=customer_id))


@bp.route("/<int:customer_id>/weight-history")
@login_required
def weight_history(customer_id):
    if not (can_access("customer_profile") or can_access("weight_management")):
        abort(403)
    customer = db.session.get(Customer, customer_id) or abort(404)
    if customer.is_deleted:
        abort(404)
    purchases = (
        Purchase.query.filter_by(customer_id=customer_id)
        .order_by(Purchase.purchase_date.desc(), Purchase.id.desc())
        .all()
    )
    return render_template("customer_profile/weight_history.html", customer=customer, purchases=purchases)


@bp.route("/<int:customer_id>/weight-history/<int:purchase_id>/edit", methods=["POST"])
@login_required
@require("weight_management")
def weight_edit(customer_id, purchase_id):
    purchase = db.session.get(Purchase, purchase_id) or abort(404)
    if purchase.customer_id != customer_id:
        abort(404)
    weight_raw = request.form.get("weight", "").strip()
    date_raw = request.form.get("purchase_date", "").strip()
    try:
        cleaned = to_en_digits(weight_raw).replace(",", "")
        weight = float(cleaned)
        if weight <= 0:
            raise ValueError
    except (ValueError, TypeError):
        flash("وزن وارد شده معتبر نیست", "error")
        return redirect(url_for("customer_profile.weight_history", customer_id=customer_id))
    try:
        purchase_date = jalali_str_to_gregorian_date(date_raw)
    except Exception:
        flash("تاریخ وارد شده معتبر نیست", "error")
        return redirect(url_for("customer_profile.weight_history", customer_id=customer_id))

    purchase.weight = weight
    purchase.purchase_date = purchase_date
    db.session.commit()
    customer_service.refresh_statuses([customer_id])
    log_action(current_user, "update", "purchase_weight", purchase.id,
               {"customer_id": customer_id, "weight": weight, "purchase_date": date_raw})
    flash("رکورد وزن ویرایش شد", "success")
    return redirect(url_for("customer_profile.weight_history", customer_id=customer_id))


@bp.route("/<int:customer_id>/weight-history/<int:purchase_id>/delete", methods=["POST"])
@login_required
@require("weight_management")
def weight_delete(customer_id, purchase_id):
    purchase = db.session.get(Purchase, purchase_id) or abort(404)
    if purchase.customer_id != customer_id:
        abort(404)
    db.session.delete(purchase)
    db.session.commit()
    customer_service.refresh_statuses([customer_id])
    log_action(current_user, "delete", "purchase_weight", purchase_id, {"customer_id": customer_id})
    flash("رکورد وزن حذف شد", "success")
    return redirect(url_for("customer_profile.weight_history", customer_id=customer_id))


@bp.route("/<int:customer_id>/photo")
@login_required
@require("customer_profile")
def photo(customer_id):
    customer = db.session.get(Customer, customer_id) or abort(404)
    if not customer.photo_path:
        abort(404)
    return photo_storage.serve_photo(customer.photo_path)


@bp.route("/<int:customer_id>/print")
@login_required
@require("customer_profile")
def print_view(customer_id):
    customer = customer_service.get_customer_with_stats(customer_id)
    if not customer:
        abort(404)
    log_action(current_user, "print", "customer", customer_id)
    return render_template("customer_profile/print.html", customer=customer)
