"""Order notification service (stub interface).

Emits the two notifications the ordering spec requires when an order is
submitted:

* a confirmation to the customer, and
* an internal notification to configured recipients.

Real email delivery is intentionally **stubbed** behind this interface: no SMTP
provider is configured in dev/alpha, so notifications are logged and returned as
structured results. To go live, implement :func:`_deliver_email` (TODO) — no
caller changes needed.
"""
from __future__ import annotations

import logging
from dataclasses import dataclass

from sqlalchemy import select
from sqlalchemy.orm import Session

from app.models.client_access import ClientAccount, ClientUser
from app.models.ordering import NotificationSetting, Order

logger = logging.getLogger("data_entry_app.ordering")


@dataclass
class NotificationResult:
    channel: str  # "customer" | "internal"
    recipients: list[str]
    subject: str
    delivered: bool
    detail: str


def get_or_create_settings(db: Session, tenant_id: str) -> NotificationSetting:
    settings = db.scalar(
        select(NotificationSetting).where(NotificationSetting.tenant_id == tenant_id)
    )
    if settings is None:
        settings = NotificationSetting(tenant_id=tenant_id)
        db.add(settings)
        db.flush()
    return settings


def _internal_recipients(settings: NotificationSetting) -> list[str]:
    if not settings.internal_recipients:
        return []
    return [part.strip() for part in settings.internal_recipients.split(",") if part.strip()]


def _customer_recipients(db: Session, order: Order) -> list[str]:
    users = db.scalars(
        select(ClientUser).where(
            ClientUser.client_account_id == order.client_account_id,
            ClientUser.status == "active",
        )
    ).all()
    return [user.email for user in users if user.email]


def _deliver_email(*, to: list[str], subject: str, body: str, from_email: str | None) -> bool:
    """Deliver an email. Stubbed — logs instead of sending.

    TODO (go-live): integrate the chosen provider (SMTP / SendGrid / SES) using
    credentials from environment variables. Return True only on confirmed
    delivery.
    """
    logger.info("ordering.email.stub to=%s subject=%s", to, subject)
    return False  # stub: nothing actually sent


def send_order_submitted_notifications(db: Session, order: Order) -> list[NotificationResult]:
    """Send customer confirmation + internal notification for a submitted order."""
    settings = get_or_create_settings(db, order.tenant_id)
    customer = db.scalar(select(ClientAccount).where(ClientAccount.id == order.client_account_id))
    customer_name = customer.name if customer else "Customer"
    order_ref = order.order_number or f"#{order.id}"
    results: list[NotificationResult] = []

    if settings.send_customer_confirmation:
        to = _customer_recipients(db, order)
        subject = f"Order {order_ref} received"
        body = (
            f"Thank you — we have received order {order_ref} for {customer_name}.\n"
            f"Lines: {len(order.lines)}. Subtotal (ex GST): {order.subtotal_ex_gst:.2f}.\n"
            "Our team will review and confirm shortly."
        )
        delivered = _deliver_email(to=to, subject=subject, body=body, from_email=settings.from_email) if to else False
        results.append(
            NotificationResult(
                channel="customer",
                recipients=to,
                subject=subject,
                delivered=delivered,
                detail="stubbed" if not delivered else "sent",
            )
        )

    internal = _internal_recipients(settings)
    subject = f"New order {order_ref} from {customer_name}"
    body = (
        f"New order {order_ref} submitted by {order.created_by_name or 'a customer user'}.\n"
        f"Customer: {customer_name}. Lines: {len(order.lines)}. "
        f"Subtotal (ex GST): {order.subtotal_ex_gst:.2f}."
    )
    delivered = _deliver_email(to=internal, subject=subject, body=body, from_email=settings.from_email) if internal else False
    results.append(
        NotificationResult(
            channel="internal",
            recipients=internal,
            subject=subject,
            delivered=delivered,
            detail="no recipients configured" if not internal else ("stubbed" if not delivered else "sent"),
        )
    )
    return results
