from __future__ import annotations

from datetime import date, timedelta
from typing import Any

from .normalizer import clean_text, normalize_date, normalize_phone


def match_filters(customer: dict[str, Any], query: dict[str, Any]) -> bool:
    customer_id = clean_text(query.get("customer_id"))
    if customer_id and customer_id != clean_text(customer.get("customer_id")):
        return False

    name = clean_text(query.get("name"))
    if name and name not in clean_text(customer.get("name")):
        return False

    phone = normalize_phone(query.get("primary_phone") or query.get("phone"))
    if phone:
        customer_phone = normalize_phone(customer.get("primary_phone"))
        if not customer_phone or phone not in customer_phone:
            return False

    birthday_month = query.get("birthday_month")
    if birthday_month:
        birthday = normalize_date(customer.get("birthday"))
        if not birthday or int(birthday.split("-")[1]) != int(birthday_month):
            return False

    tags = query.get("tags") or []
    if query.get("tag"):
        tags = [query["tag"], *tags]
    if tags:
        customer_tags = set(customer.get("tags", []))
        if not set(tags).issubset(customer_tags):
            return False

    dynamic_filters = query.get("dynamic_filters") or []
    field_map = customer.get("dynamic_field_map", {})
    for item in dynamic_filters:
        field_key = item.get("field_key") or item.get("field")
        if not field_key:
            return False
        data = field_map.get(field_key)
        if not data:
            data = next(
                (
                    candidate
                    for candidate in field_map.values()
                    if clean_text(candidate.get("label")) == clean_text(field_key)
                ),
                None,
            )
        if not data:
            return False
        op = item.get("op", "contains")
        expected = clean_text(item.get("value"))
        actual = clean_text(data.get("displayValue") or data.get("value"))
        if op == "eq" and actual != expected:
            return False
        if op == "contains" and expected not in actual:
            return False
    return True


def sort_customers(customers: list[dict[str, Any]]) -> list[dict[str, Any]]:
    return sorted(
        customers,
        key=lambda item: (
            item.get("birthday") or "9999-12-31",
            item.get("name") or "",
        ),
    )


def select_due_fields(customer: dict[str, Any]) -> list[dict[str, Any]]:
    results = []
    for field_key, value in customer.get("dynamic_field_map", {}).items():
        label = clean_text(value.get("label", ""))
        normalized = normalize_date(value.get("value"))
        if not normalized:
            continue
        if any(keyword in label for keyword in ["到期", "续费", "回访", "预约"]):
            results.append(
                {
                    "field_key": field_key,
                    "label": label,
                    "date": normalized,
                    "display_value": value.get("displayValue") or value.get("value"),
                }
            )
    return results


def query_due_within_days(customers: list[dict[str, Any]], days: int) -> list[dict[str, Any]]:
    today = date.today()
    end_date = today + timedelta(days=days)
    matched: list[dict[str, Any]] = []
    for customer in customers:
        due_fields = []
        for item in select_due_fields(customer):
            due_date = date.fromisoformat(item["date"])
            if today <= due_date <= end_date:
                due_fields.append(item)
        if due_fields:
            cloned = dict(customer)
            cloned["due_fields"] = due_fields
            matched.append(cloned)
    return matched
