"""کوئری‌های صفحه تسک — پورت‌شده از core/repositories/task_repo.py دسکتاپ.

منطق دسته‌بندی تسک‌ها (نام‌ها و رنگ‌ها طبق config.py ثابت مونده، فقط منطق زیرشون تغییر کرده):
- تماس امروز (قرمز): تاریخ تماس بعدیِ مشتری = امروز
- VIP بدون خرید (سبز): مشتری با تگ VIP که بیش از ۲ هفته از آخرین تماسش گذشته
- مشتری خوابیده (زرد): هر مشتری‌ای که بیش از ۲ ماه از آخرین تماسش گذشته (بدون شرط تگ)
- پرزنت نشده (آبی): هیچ‌وقت تماس نگرفته و مجموع وزن خریدش صفر است
- تماس هفته آینده (بنفش): تاریخ تماس بعدیِ مشتری در بازه‌ی هفته‌ی تقویمی آینده است
- پیگیری این هفته (صورتی): مشتری‌هایی که تگ «پیگیری هفته آینده» دارند
"""
from datetime import date, datetime, timedelta

from sqlalchemy import func

from app.extensions import db
from app.models.customer import Customer, Purchase
from app.models.call import Call
from app.models.tag import Tag, CustomerTag
from app.services.jalali import next_week_range

FOLLOW_UP_TAG_NAME = "پیگیری هفته آینده"


def _cutoff_datetime(days: int) -> datetime:
    return datetime.now() - timedelta(days=days)


def _stats_query():
    stats = (
        db.session.query(
            Purchase.customer_id.label("customer_id"),
            func.sum(Purchase.amount).label("total_amount"),
            func.sum(Purchase.weight).label("total_weight"),
            func.max(Purchase.purchase_date).label("last_purchase_date"),
        )
        .group_by(Purchase.customer_id)
        .subquery()
    )
    calls = (
        db.session.query(Call.customer_id.label("customer_id"), func.max(Call.call_date).label("last_call_date"))
        .group_by(Call.customer_id)
        .subquery()
    )
    query = (
        db.session.query(
            Customer,
            func.coalesce(stats.c.total_amount, 0).label("total_amount"),
            func.coalesce(stats.c.total_weight, 0).label("total_weight"),
            stats.c.last_purchase_date,
            calls.c.last_call_date,
        )
        .outerjoin(stats, stats.c.customer_id == Customer.id)
        .outerjoin(calls, calls.c.customer_id == Customer.id)
        .filter(Customer.is_deleted.is_(False))
    )
    return query, stats, calls


def _finalize(rows):
    results = []
    for customer, total_amount, total_weight, last_purchase_date, last_call_date in rows:
        customer.computed_total_amount = total_amount or 0
        customer.computed_total_weight = total_weight or 0
        customer.computed_last_purchase_date = last_purchase_date
        customer.computed_last_call_date = last_call_date
        results.append(customer)
    return results


def call_today():
    query, _stats, _calls = _stats_query()
    query = query.filter(Customer.next_call_date == date.today()).order_by(Customer.first_name)
    return _finalize(query.all())


def call_next_week():
    start, end = next_week_range()
    query, _stats, _calls = _stats_query()
    query = query.filter(Customer.next_call_date.between(start, end)).order_by(Customer.next_call_date)
    return _finalize(query.all())


def vip_inactive(days=14):
    cutoff = _cutoff_datetime(days)
    query, _stats, calls = _stats_query()
    vip_ids = (
        db.session.query(CustomerTag.customer_id)
        .join(Tag, Tag.id == CustomerTag.tag_id)
        .filter(Tag.name == "VIP")
    )
    query = query.filter(
        Customer.id.in_(vip_ids),
        db.or_(calls.c.last_call_date.is_(None), calls.c.last_call_date < cutoff),
    ).order_by(Customer.first_name)
    return _finalize(query.all())


def sleeping(days=60):
    cutoff = _cutoff_datetime(days)
    query, _stats, calls = _stats_query()
    query = query.filter(
        db.or_(calls.c.last_call_date.is_(None), calls.c.last_call_date < cutoff)
    ).order_by(Customer.first_name)
    return _finalize(query.all())


def not_presented():
    query, stats, calls = _stats_query()
    query = query.filter(
        calls.c.last_call_date.is_(None),
        db.or_(stats.c.total_weight.is_(None), stats.c.total_weight == 0),
    ).order_by(Customer.joined_at.desc())
    return _finalize(query.all())


def follow_up_week():
    query, _stats, _calls = _stats_query()
    tagged_ids = (
        db.session.query(CustomerTag.customer_id)
        .join(Tag, Tag.id == CustomerTag.tag_id)
        .filter(Tag.name == FOLLOW_UP_TAG_NAME)
    )
    query = query.filter(Customer.id.in_(tagged_ids)).order_by(Customer.first_name)
    return _finalize(query.all())


CATEGORY_FUNCS = {
    "call_today": call_today,
    "vip_inactive": vip_inactive,
    "sleeping": sleeping,
    "not_presented": not_presented,
    "call_next_week": call_next_week,
    "follow_up_week": follow_up_week,
}


def get_category_customers(key):
    fn = CATEGORY_FUNCS.get(key)
    return fn() if fn else []


def get_category_counts():
    return {key: len(fn()) for key, fn in CATEGORY_FUNCS.items()}
