import logging
from typing import Any, Dict, List, Optional

from app.core.database import execute_query

logger = logging.getLogger(__name__)


def _to_float(value: Any, default: float = 0.0) -> float:
    if value is None:
        return default
    try:
        return float(value)
    except (TypeError, ValueError):
        return default


def _apply_common_filters(
    base_query: str,
    params: List[Any],
    customer_id: Optional[int],
    sag_id: Optional[int],
    q: Optional[str],
    customer_alias: str,
    sag_alias: str,
    description_alias: str,
) -> tuple[str, List[Any]]:
    query = base_query

    if customer_id:
        query += f" AND {customer_alias}.id = %s"
        params.append(customer_id)
    if sag_id:
        query += f" AND {sag_alias}.id = %s"
        params.append(sag_id)
    if q:
        like = f"%{q.lower()}%"
        query += (
            f" AND (LOWER({description_alias}) LIKE %s"
            f" OR LOWER(COALESCE({sag_alias}.titel, '')) LIKE %s"
            f" OR LOWER(COALESCE({customer_alias}.name, '')) LIKE %s)"
        )
        params.extend([like, like, like])

    return query, params


def _fetch_sales_lines(customer_id: Optional[int], sag_id: Optional[int], q: Optional[str]) -> List[Dict[str, Any]]:
    query = """
        SELECT
            si.id,
            si.sag_id,
            s.titel AS sag_title,
            s.customer_id,
            c.name AS customer_name,
            si.description,
            si.quantity,
            si.unit,
            si.unit_price,
            si.amount,
            si.currency,
            si.status,
            si.line_date,
            si.product_id
        FROM sag_salgsvarer si
        JOIN sag_sager s ON s.id = si.sag_id
        LEFT JOIN customers c ON c.id = s.customer_id
        WHERE s.deleted_at IS NULL
          AND LOWER(si.type) = 'sale'
          AND LOWER(si.status) != 'cancelled'
    """
    params: List[Any] = []
    query, params = _apply_common_filters(query, params, customer_id, sag_id, q, "c", "s", "si.description")
    query += " ORDER BY si.line_date DESC NULLS LAST, si.id DESC"

    rows = execute_query(query, tuple(params)) or []
    lines: List[Dict[str, Any]] = []
    for row in rows:
        qty = _to_float(row.get("quantity"), 0.0)
        unit_price = _to_float(row.get("unit_price"), 0.0)
        amount = _to_float(row.get("amount"), qty * unit_price)
        lines.append(
            {
                "line_key": f"sale:{row['id']}",
                "source_type": "sale",
                "source_id": row["id"],
                "reference_id": row["id"],
                "sag_id": row.get("sag_id"),
                "sag_title": row.get("sag_title"),
                "customer_id": row.get("customer_id"),
                "customer_name": row.get("customer_name"),
                "description": row.get("description") or "Salgslinje",
                "quantity": qty if qty > 0 else 1.0,
                "unit": row.get("unit") or "stk",
                "unit_price": unit_price,
                "discount_percentage": 0.0,
                "amount": amount,
                "currency": row.get("currency") or "DKK",
                "status": row.get("status") or "draft",
                "line_date": str(row.get("line_date")) if row.get("line_date") else None,
                "product_id": row.get("product_id"),
                "selected": True,
            }
        )

    return lines


def _fetch_subscription_lines(customer_id: Optional[int], sag_id: Optional[int], q: Optional[str]) -> List[Dict[str, Any]]:
    query = """
        SELECT
            i.id,
            i.subscription_id,
            i.line_no,
            i.product_id,
            i.description,
            i.quantity,
            i.unit_price,
            i.line_total,
            s.id AS sub_id,
            s.subscription_number,
            s.status AS subscription_status,
            s.billing_interval,
            s.sag_id,
            sg.titel AS sag_title,
            s.customer_id,
            c.name AS customer_name
        FROM sag_subscription_items i
        JOIN sag_subscriptions s ON s.id = i.subscription_id
        JOIN sag_sager sg ON sg.id = s.sag_id
        LEFT JOIN customers c ON c.id = s.customer_id
        WHERE sg.deleted_at IS NULL
          AND LOWER(s.status) IN ('draft', 'active', 'paused')
    """
    params: List[Any] = []
    query, params = _apply_common_filters(query, params, customer_id, sag_id, q, "c", "sg", "i.description")
    query += " ORDER BY s.id DESC, i.line_no ASC, i.id ASC"

    rows = execute_query(query, tuple(params)) or []
    lines: List[Dict[str, Any]] = []
    for row in rows:
        qty = _to_float(row.get("quantity"), 1.0)
        unit_price = _to_float(row.get("unit_price"), 0.0)
        amount = _to_float(row.get("line_total"), qty * unit_price)
        lines.append(
            {
                "line_key": f"subscription:{row['id']}",
                "source_type": "subscription",
                "source_id": row["id"],
                "reference_id": row.get("subscription_id"),
                "subscription_number": row.get("subscription_number"),
                "sag_id": row.get("sag_id"),
                "sag_title": row.get("sag_title"),
                "customer_id": row.get("customer_id"),
                "customer_name": row.get("customer_name"),
                "description": row.get("description") or "Abonnementslinje",
                "quantity": qty if qty > 0 else 1.0,
                "unit": "stk",
                "unit_price": unit_price,
                "discount_percentage": 0.0,
                "amount": amount,
                "currency": "DKK",
                "status": row.get("subscription_status") or "draft",
                "line_date": None,
                "product_id": row.get("product_id"),
                "selected": True,
                "meta": {
                    "billing_interval": row.get("billing_interval"),
                    "line_no": row.get("line_no"),
                },
            }
        )

    return lines


def _fetch_hardware_lines(customer_id: Optional[int], sag_id: Optional[int], q: Optional[str]) -> List[Dict[str, Any]]:
    query = """
        SELECT
            sh.id AS relation_id,
            sh.sag_id,
            sh.note,
            s.titel AS sag_title,
            s.customer_id,
            c.name AS customer_name,
            h.id AS hardware_id,
            h.asset_type,
            h.brand,
            h.model,
            h.serial_number,
            h.status AS hardware_status
        FROM sag_hardware sh
        JOIN sag_sager s ON s.id = sh.sag_id
        JOIN hardware_assets h ON h.id = sh.hardware_id
        LEFT JOIN customers c ON c.id = s.customer_id
        WHERE sh.deleted_at IS NULL
          AND s.deleted_at IS NULL
          AND h.deleted_at IS NULL
    """
    params: List[Any] = []
    query, params = _apply_common_filters(
        query,
        params,
        customer_id,
        sag_id,
        q,
        "c",
        "s",
        "CONCAT(COALESCE(h.brand, ''), ' ', COALESCE(h.model, ''), ' ', COALESCE(h.serial_number, ''))",
    )
    query += " ORDER BY sh.id DESC"

    rows = execute_query(query, tuple(params)) or []
    lines: List[Dict[str, Any]] = []
    for row in rows:
        serial = row.get("serial_number")
        serial_part = f" (S/N: {serial})" if serial else ""
        brand_model = " ".join([part for part in [row.get("brand"), row.get("model")] if part]).strip()
        label = brand_model or row.get("asset_type") or "Hardware"
        desc = f"Hardware: {label}{serial_part}"
        if row.get("note"):
            desc = f"{desc} - {row['note']}"

        lines.append(
            {
                "line_key": f"hardware:{row['relation_id']}",
                "source_type": "hardware",
                "source_id": row["relation_id"],
                "reference_id": row.get("hardware_id"),
                "sag_id": row.get("sag_id"),
                "sag_title": row.get("sag_title"),
                "customer_id": row.get("customer_id"),
                "customer_name": row.get("customer_name"),
                "description": desc,
                "quantity": 1.0,
                "unit": "stk",
                "unit_price": 0.0,
                "discount_percentage": 0.0,
                "amount": 0.0,
                "currency": "DKK",
                "status": row.get("hardware_status") or "active",
                "line_date": None,
                "product_id": None,
                "selected": True,
            }
        )

    return lines


def aggregate_order_lines(
    customer_id: Optional[int] = None,
    sag_id: Optional[int] = None,
    q: Optional[str] = None,
) -> Dict[str, Any]:
    """Aggregate order-ready lines across sale, subscription and hardware sources."""
    sales_lines = _fetch_sales_lines(customer_id=customer_id, sag_id=sag_id, q=q)
    subscription_lines = _fetch_subscription_lines(customer_id=customer_id, sag_id=sag_id, q=q)
    hardware_lines = _fetch_hardware_lines(customer_id=customer_id, sag_id=sag_id, q=q)

    all_lines = sales_lines + subscription_lines + hardware_lines

    total_amount = sum(_to_float(line.get("amount")) for line in all_lines)
    selected_amount = sum(_to_float(line.get("amount")) for line in all_lines if line.get("selected"))

    customer_ids = sorted(
        {
            int(line["customer_id"])
            for line in all_lines
            if line.get("customer_id") is not None
        }
    )

    return {
        "lines": all_lines,
        "summary": {
            "line_count": len(all_lines),
            "line_count_sales": len(sales_lines),
            "line_count_subscriptions": len(subscription_lines),
            "line_count_hardware": len(hardware_lines),
            "customer_count": len(customer_ids),
            "total_amount": round(total_amount, 2),
            "selected_amount": round(selected_amount, 2),
            "currency": "DKK",
        },
    }
