"""مسیرهای گزارشات مشتریان، فروشندگان و تماس‌ها."""

import io
from collections import Counter
from datetime import timedelta

from flask import Blueprint, render_template, request, send_file, abort, redirect, url_for
from flask_login import login_required, current_user
from sqlalchemy.orm import selectinload

from app.extensions import db
from app.models.customer import Customer
from app.models.user import User
from app.models.call import Call
from app.models.tag import CallTag
from app.services.permissions import require
from app.services.activity_logger import log_action
from app.services import customer_service, reports as reports_service, tag_service, listing
from app.services.jalali import jalali_str_to_gregorian_date, iran_day_start_utc, to_en_digits


bp = Blueprint("reports", __name__, url_prefix="/reports")


# ============================================================
# کمک‌توابع خواندن فیلترها
# (ورودی نامعتبر نادیده گرفته می‌شه، نه خطای سرور)
# ============================================================

def _parse_date(args, key):
    raw = args.get(key, "").strip()
    if not raw:
        return None
    try:
        return jalali_str_to_gregorian_date(raw)
    except Exception:
        return None


def _parse_float(args, key):
    raw = args.get(key, "").strip()
    if not raw:
        return None
    try:
        return float(to_en_digits(raw).replace(",", ""))
    except ValueError:
        return None


def _parse_ids(args, key):
    return [int(v) for v in args.getlist(key) if v.isdigit()]


def _parse_answered(args):
    return {"1": True, "0": False}.get(args.get("answered"))


# ============================================================
# فیلتر گزارش مشتریان
# ============================================================

def _parse_customer_filters(args):
    return {
        "cities": args.getlist("cities") or None,
        "tag_ids": _parse_ids(args, "tag_ids") or None,
        "min_weight": _parse_float(args, "min_weight"),
        "max_weight": _parse_float(args, "max_weight"),
        "date_from": _parse_date(args, "date_from"),
        "date_to": _parse_date(args, "date_to"),
        "time_mode": args.get("time_mode", "none"),
        "sort": args.get("sort", "weight_desc"),
    }


# ============================================================
# فیلتر گزارش فروشندگان و گزارش تماس‌ها
# ============================================================

def _parse_call_filters(args, with_search=True):
    filters = {
        "salesperson_ids": _parse_ids(args, "salesperson_ids") or None,
        "tag_ids": _parse_ids(args, "tag_ids") or None,
        "date_from": _parse_date(args, "date_from"),
        "date_to": _parse_date(args, "date_to"),
        "answered": _parse_answered(args),
        "sort": args.get("sort", "date_desc"),
    }
    if with_search:
        filters["search"] = args.get("q", "").strip()
    return filters


# ============================================================
# ساخت گزارش تماس‌ها
# ============================================================

def _build_calls_report(
    salesperson_ids=None,
    tag_ids=None,
    date_from=None,
    date_to=None,
    answered=None,
    search=None,
    sort="date_desc",
):
    """
    گزارش تمام تماس‌ها.

    هر تماس یک ردیف مستقل است.

    اگر یک مشتری 20 تماس داشته باشد،
    هر 20 تماس به صورت جداگانه نمایش داده می‌شود.

    اگر چند تگ انتخاب شود،
    تماس‌هایی نمایش داده می‌شوند که حداقل
    یکی از تگ‌های انتخاب‌شده را داشته باشند.
    """

    query = (
        Call.query
        .join(Customer, Call.customer_id == Customer.id)
        .outerjoin(User, Call.salesperson_id == User.id)
        .options(selectinload(Call.customer), selectinload(Call.salesperson))
    )

    # --------------------------------------------------------
    # فیلتر فروشنده
    # --------------------------------------------------------

    if salesperson_ids:
        query = query.filter(
            Call.salesperson_id.in_(salesperson_ids)
        )

    # --------------------------------------------------------
    # فیلتر تگ
    # --------------------------------------------------------

    if tag_ids:
        query = (
            query
            .join(
                CallTag,
                CallTag.call_id == Call.id
            )
            .filter(
                CallTag.tag_id.in_(tag_ids)
            )
            .distinct()
        )

    # --------------------------------------------------------
    # فیلتر تاریخ
    #
    # call_date به UTC ذخیره می‌شه؛ مرز روزها به وقت ایران
    # حساب می‌شه و «تا تاریخ» کل همون روز رو هم شامل می‌شه.
    # --------------------------------------------------------

    if date_from:
        query = query.filter(
            Call.call_date >= iran_day_start_utc(date_from)
        )

    if date_to:
        query = query.filter(
            Call.call_date < iran_day_start_utc(date_to + timedelta(days=1))
        )

    # --------------------------------------------------------
    # فیلتر پاسخ
    # --------------------------------------------------------

    if answered is not None:
        query = query.filter(
            Call.answered.is_(answered)
        )

    # --------------------------------------------------------
    # جستجو (نتیجه تماس، نام/نام کامل، شماره حتی با عدد فارسی)
    # --------------------------------------------------------

    if search:
        query = query.filter(
            db.or_(
                Call.result_text.icontains(search, autoescape=True),
                customer_service.search_condition(search),
            )
        )

    # --------------------------------------------------------
    # مرتب‌سازی
    # --------------------------------------------------------

    if sort == "date_asc":

        query = query.order_by(
            Call.call_date.asc()
        )

    elif sort == "salesperson_asc":

        query = query.order_by(
            User.full_name.asc(),
            Call.call_date.desc()
        )

    elif sort == "salesperson_desc":

        query = query.order_by(
            User.full_name.desc(),
            Call.call_date.desc()
        )

    elif sort in ("salesperson_calls_desc", "salesperson_calls_asc"):

        # فروشنده‌ای که (در همین فیلترها) تماس بیشتری/کمتری داشته اول؛
        # تماس‌های هر فروشنده کنار هم و به ترتیب تاریخ
        calls = query.order_by(Call.call_date.desc()).all()
        counts = Counter(c.salesperson_id for c in calls)
        calls.sort(
            key=lambda c: (counts[c.salesperson_id], c.salesperson_id or 0),
            reverse=(sort == "salesperson_calls_desc")
        )
        return calls

    else:

        query = query.order_by(
            Call.call_date.desc()
        )

    return query.all()


# ============================================================
# صفحه اصلی گزارشات
# ============================================================

@bp.route("/")
@login_required
@require("reports")
def index():
    return redirect(
        url_for("reports.customers")
    )


# ============================================================
# گزارش مشتری‌ها
# ============================================================

@bp.route("/customers")
@login_required
@require("reports")
def customers():

    filters = _parse_customer_filters(
        request.args
    )

    all_rows = reports_service.build_customer_report(
        **filters
    )

    if request.args:

        log_action(
            current_user,
            "report",
            "customer",
            details={
                "count": len(all_rows),
                "tag_ids": filters.get("tag_ids") or [],
            },
        )

    return render_template(
        "reports/customers.html",

        cities=customer_service.distinct_cities(),

        tag_groups=tag_service.all_tags_grouped(),

        rows=listing.cut(all_rows),

        total=len(all_rows),

        has_range=bool(filters["date_from"] or filters["date_to"]),

        args=request.args,
    )


# ============================================================
# خروجی گزارش مشتری‌ها
# ============================================================

@bp.route("/customers/export.<fmt>")
@login_required
@require("reports")
def customers_export(fmt):

    if fmt not in ("xlsx", "pdf"):
        abort(404)

    filters = _parse_customer_filters(
        request.args
    )

    rows = reports_service.build_customer_report(
        **filters
    )

    buffer = io.BytesIO()

    if fmt == "xlsx":

        reports_service.export_customers_excel(
            rows,
            buffer
        )

        mimetype = (
            "application/vnd.openxmlformats-officedocument."
            "spreadsheetml.sheet"
        )

    else:

        reports_service.export_customers_pdf(
            rows,
            buffer
        )

        mimetype = "application/pdf"

    buffer.seek(0)

    log_action(
        current_user,
        "export",
        "customer_report",
        details={
            "format": fmt,
            "count": len(rows),
            "tag_ids": filters.get("tag_ids") or [],
        },
    )

    return send_file(
        buffer,
        mimetype=mimetype,
        as_attachment=True,
        download_name=f"گزارش-مشتریان.{fmt}",
    )


# ============================================================
# گزارش فروشندگان
# ============================================================

@bp.route("/salespeople")
@login_required
@require("reports")
def salespeople():

    filters = _parse_call_filters(
        request.args,
        with_search=False
    )

    # نکته مهم:
    # اینجا عمداً از گزارش تماس‌ها استفاده می‌کنیم
    # تا فیلتر تگ روی خود تماس اعمال شود.
    all_calls = _build_calls_report(
        **filters
    )

    if request.args:

        log_action(
            current_user,
            "report",
            "salesperson",
            details={
                "count": len(all_calls),
                "tag_ids": filters.get("tag_ids") or [],
                "salesperson_ids": filters.get("salesperson_ids") or [],
            },
        )

    return render_template(
        "reports/salespeople.html",

        salespeople=(
            User.query
            .order_by(User.full_name)
            .all()
        ),

        # تمام دسته‌بندی‌ها و تگ‌ها
        tag_groups=tag_service.all_tags_grouped(),

        calls=listing.cut(all_calls),

        total=len(all_calls),

        args=request.args,
    )


# ============================================================
# خروجی گزارش فروشندگان
# ============================================================

@bp.route("/salespeople/export.<fmt>")
@login_required
@require("reports")
def salespeople_export(fmt):

    if fmt not in ("xlsx", "pdf"):
        abort(404)

    filters = _parse_call_filters(
        request.args,
        with_search=False
    )

    # حتماً همین گزارش را استفاده می‌کنیم
    # تا Excel و PDF هم دقیقاً همان فیلتر تگ را داشته باشند.
    calls = _build_calls_report(
        **filters
    )

    buffer = io.BytesIO()

    if fmt == "xlsx":

        reports_service.export_salespeople_excel(
            calls,
            buffer
        )

        mimetype = (
            "application/vnd.openxmlformats-officedocument."
            "spreadsheetml.sheet"
        )

    else:

        reports_service.export_salespeople_pdf(
            calls,
            buffer
        )

        mimetype = "application/pdf"

    buffer.seek(0)

    log_action(
        current_user,
        "export",
        "salesperson_report",
        details={
            "format": fmt,
            "count": len(calls),
            "tag_ids": filters.get("tag_ids") or [],
            "salesperson_ids": filters.get("salesperson_ids") or [],
        },
    )

    return send_file(
        buffer,
        mimetype=mimetype,
        as_attachment=True,
        download_name=f"گزارش-فروشنده‌ها.{fmt}",
    )


# ============================================================
# گزارش تماس‌ها
# ============================================================

@bp.route("/calls")
@login_required
@require("reports")
def calls():

    filters = _parse_call_filters(
        request.args
    )

    all_calls = _build_calls_report(
        **filters
    )

    if request.args:

        log_action(
            current_user,
            "report",
            "calls",
            details={
                "count": len(all_calls),
                "tag_ids": filters.get("tag_ids") or [],
                "salesperson_ids": filters.get("salesperson_ids") or [],
            },
        )

    return render_template(
        "reports/calls.html",

        calls=listing.cut(all_calls),

        total=len(all_calls),

        salespeople=(
            User.query
            .order_by(User.full_name)
            .all()
        ),

        tag_groups=tag_service.all_tags_grouped(),

        args=request.args,
    )
