"""
Printing domain services.

This module is intended for reusable business logic that may be called by:
- management commands
- API views
- signal handlers
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING
from urllib.parse import urlparse

from django.conf import settings
from django.utils import timezone

from api_v1.utils.wecom_webhook import send_wecom_webhook_message

if TYPE_CHECKING:
    from printing.models import PrintingJob


@dataclass(frozen=True)
class PrintingJobLatestState:
    state_name: str
    advanced_at: str


def build_printing_job_followup_url(*, printing_order_id: int | None) -> str:
    tmpl = getattr(
        settings,
        "PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE",
        "",
    )
    tmpl = (str(tmpl or "")).strip()
    if not tmpl:
        return ""
    oid = printing_order_id if printing_order_id is not None else ""
    try:
        return str(tmpl).format(order_id=str(oid))
    except Exception:
        # template mis-config should not crash critical flows
        return f"https://app.yuwen.cloud/workstation/production/batch-advance?orderId={oid}"


def _truncate_text(s: str, max_len: int) -> str:
    s = s or ""
    if len(s) <= max_len:
        return s
    return s[: max(0, int(max_len) - 6)] + "...(截断)"


def _is_http_url(s: str) -> bool:
    """
    Minimal URL check for markdown linkify.
    Only treat http/https absolute URLs as linkable.
    """
    s = (s or "").strip()
    if not s:
        return False
    try:
        p = urlparse(s)
    except Exception:
        return False
    return p.scheme in ("http", "https") and bool(p.netloc)


def _escape_markdown_link_text(s: str) -> str:
    # avoid breaking markdown link text
    return (s or "").replace("[", r"\[").replace("]", r"\]")


def render_process_params_markdown(*, params: dict, max_items: int = 60, max_value_len: int = 200) -> str:
    """
    Render process params as markdown lines.
    Example:
      - **温度**：25
    """
    if not params:
        return "- （无）"

    items = []
    for k in sorted(params.keys(), key=lambda x: str(x)):
        v = params.get(k)
        kk = _truncate_text(str(k), 80)
        v_str = "" if v is None else str(v)
        v_href = v_str.strip()
        if _is_http_url(v_href):
            v_disp = _escape_markdown_link_text(_truncate_text(v_href, int(max_value_len)))
            vv = f"[{v_disp}]({v_href})"
        else:
            vv = _truncate_text(v_str, int(max_value_len))
        items.append(f"- **{kk}**：{vv}")

    if len(items) > int(max_items):
        remain = len(items) - int(max_items)
        items = items[: int(max_items)] + [f"- ……（其余 {remain} 项已省略）"]
    return "\n".join(items)


def _user_label(user) -> str:
    """
    Format a human-readable sender label from Django User.
    Prefer employee.name if available.
    """
    if not user:
        return "系统自动发送"
    emp = getattr(user, "employee", None)
    name = getattr(emp, "name", None) if emp is not None else None
    if name:
        return str(name)
    username = getattr(user, "username", None)
    if username:
        return str(username)
    return "系统自动发送"


def get_printing_job_latest_state(*, job: PrintingJob) -> PrintingJobLatestState:
    """
    Latest state is defined as the latest non-cancelled StateFlowRecord
    on job.business_object.
    """
    if not job.business_object:
        raise ValueError(f"PrintingJob 未绑定 business_object，无法获取状态：id={job.id}")

    state_log = (
        job.business_object.state_logs.filter(is_cancelled=False)
        .select_related("state")
        .order_by("-completed_at", "-id")
        .first()
    )
    if state_log is None:
        return PrintingJobLatestState(state_name="未开始", advanced_at="-")

    state_name = getattr(state_log.state, "name", None) or str(state_log.state)
    advanced_at_dt = state_log.completed_at
    advanced_at = timezone.localtime(advanced_at_dt).strftime("%Y-%m-%d %H:%M:%S")
    return PrintingJobLatestState(state_name=str(state_name), advanced_at=str(advanced_at))


def render_printing_job_state_markdown(
    *,
    printing_order_id: str,
    printing_job_id: str,
    state_name: str,
    advanced_at: str,
    sender_label: str,
    followup_url: str,
    process_params_markdown: str,
) -> str:
    template = getattr(
        settings,
        "PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE",
        (
            "### 印染任务状态推进\n"
            "\n"
            "- **印染订单ID**：`{printing_order_id}`\n"
            "- **印染任务ID**：`{printing_job_id}`\n"
            "- **推进状态**：**{state_name}**\n"
            "- **推进时间**：`{advanced_at}`\n"
            "- **发送者**：{sender}\n"
            "{followup_line}"
            "\n"
            "**工序参数**：\n"
            "{process_params_markdown}\n"
        ),
    )
    followup_url = (followup_url or "").strip()
    followup_line = f"- **跟进地址**：[{followup_url}]({followup_url})\n" if followup_url else ""
    return template.format(
        printing_order_id=str(printing_order_id),
        printing_job_id=str(printing_job_id),
        state_name=str(state_name),
        advanced_at=str(advanced_at),
        sender=str(sender_label or "系统自动发送"),
        followup_line=str(followup_line),
        process_params_markdown=str(process_params_markdown),
    )


def send_printing_job_latest_state_wecom(
    *,
    printing_job_id: int,
    sender_label: str,
    key: str | None = None,
    timeout_seconds: float = 10.0,
    dry_run: bool = False,
) -> dict:
    """
    Reusable entrypoint for command / future API.
    """
    from printing.models import PrintingJob
    job = (
        PrintingJob.objects.select_related("printing_order", "business_object")
        .filter(id=int(printing_job_id))
        .first()
    )
    if not job:
        raise ValueError(f"PrintingJob 不存在：id={printing_job_id}")

    # latest state log for parameters
    state_log = (
        job.business_object.state_logs.filter(is_cancelled=False)
        .select_related("state")
        .order_by("-completed_at", "-id")
        .first()
        if job.business_object
        else None
    )
    if state_log is None:
        state_name = "未开始"
        advanced_at = "-"
        params = {}
    else:
        state_name = getattr(state_log.state, "name", None) or str(state_log.state)
        advanced_at = timezone.localtime(state_log.completed_at).strftime("%Y-%m-%d %H:%M:%S")
        params = state_log.get_all_parameters_summary(include_cancelled=False)

    followup_url = build_printing_job_followup_url(printing_order_id=job.printing_order_id)
    process_params_markdown = render_process_params_markdown(params=params)
    msg = render_printing_job_state_markdown(
        printing_order_id=str(job.printing_order_id),
        printing_job_id=str(job.id),
        state_name=str(state_name),
        advanced_at=str(advanced_at),
        sender_label=sender_label,
        followup_url=followup_url,
        process_params_markdown=process_params_markdown,
    )

    if dry_run:
        return {
            "dry_run": True,
            "message": msg,
            "state_name": str(state_name),
            "advanced_at": str(advanced_at),
            "followup_url": str(followup_url),
            "process_params": params,
        }

    resp = send_wecom_webhook_message(
        content=msg,
        msgtype="markdown",
        key=key,
        timeout_seconds=timeout_seconds,
    )
    return {
        "dry_run": False,
        "message": msg,
        "state_name": str(state_name),
        "advanced_at": str(advanced_at),
        "followup_url": str(followup_url),
        "process_params": params,
        "wecom": resp.raw,
        "ok": resp.ok,
        "errcode": resp.errcode,
        "errmsg": resp.errmsg,
    }


def render_printing_order_created_markdown(
    *,
    printing_order_id: str,
    printing_order_human_id: str,
    created_at: str,
    sender_label: str,
    customer_name: str,
    fabric: str,
    outgoing_date: str,
) -> str:
    template = getattr(
        settings,
        "PRINTING_ORDER_CREATED_WECOM_MARKDOWN_TEMPLATE",
        (
            "### 印染订单创建\n"
            "\n"
            "- **印染订单ID**：`{printing_order_id}`\n"
            "- **订单编号**：`{printing_order_human_id}`\n"
            "- **创建时间**：`{created_at}`\n"
            "- **发送者**：{sender}\n"
            "- **客户**：{customer_name}\n"
            "- **面料**：{fabric}\n"
            "- **出货日期**：`{outgoing_date}`\n"
        ),
    )
    return template.format(
        printing_order_id=str(printing_order_id),
        printing_order_human_id=str(printing_order_human_id),
        created_at=str(created_at),
        sender=str(sender_label or "系统自动发送"),
        customer_name=str(customer_name or "-"),
        fabric=str(fabric or "-"),
        outgoing_date=str(outgoing_date or "-"),
    )


def render_printing_job_production_completed_markdown(
    *,
    printing_order_identifier: str,
    printing_job_id: str,
    product_name: str,
    unshipped_sales_items_count: str,
    unshipped_sales_items_quantity: str,
    sender_label: str,
) -> str:
    template = getattr(
        settings,
        "PRINTING_JOB_PRODUCTION_COMPLETED_WECOM_MARKDOWN_TEMPLATE",
        (
            "### 印染任务已完成生产\n"
            "\n"
            "- **订单号**：`{printing_order_identifier}`\n"
            "- **印染任务ID**：`{printing_job_id}`\n"
            "- **产品名称**：{product_name}\n"
            "- **未出货销售品条数**：`{unshipped_sales_items_count}`\n"
            "- **未出货销售品数量**：`{unshipped_sales_items_quantity}`\n"
            "- **发送者**：{sender}\n"
        ),
    )
    return template.format(
        printing_order_identifier=str(printing_order_identifier or "-"),
        printing_job_id=str(printing_job_id or "-"),
        product_name=str(product_name or "-"),
        unshipped_sales_items_count=str(unshipped_sales_items_count or "0"),
        unshipped_sales_items_quantity=str(unshipped_sales_items_quantity or "0"),
        sender=str(sender_label or "系统自动发送"),
    )


def send_printing_job_production_completed_wecom(
    *,
    printing_job_id: int,
    triggered_by_id: int | None = None,
    key: str | None = None,
    timeout_seconds: float = 10.0,
    dry_run: bool = False,
) -> dict:
    from django.contrib.auth import get_user_model
    from django.db.models import Sum
    from printing.models import PrintingJob
    from shipment.services import get_active_sales_items_queryset

    job = (
        PrintingJob.objects.select_related("product", "printing_order")
        .filter(id=int(printing_job_id))
        .first()
    )
    if not job:
        raise ValueError(f"PrintingJob 不存在：id={printing_job_id}")

    triggered_by = None
    if triggered_by_id:
        triggered_by = get_user_model().objects.filter(id=int(triggered_by_id)).first()

    order = getattr(job, "printing_order", None)
    external_order_id = str(getattr(order, "external_order_id", "") or "").strip()
    printing_order_identifier = external_order_id or str(getattr(order, "id", "-") or "-")
    product_name = getattr(getattr(job, "product", None), "name", None) or "-"
    unshipped_sales_items_qs = get_active_sales_items_queryset().filter(
        printing_job_id=job.id,
        shipment__isnull=True,
    )
    unshipped_sales_items_count = unshipped_sales_items_qs.count()
    unshipped_sales_items_quantity = (
        unshipped_sales_items_qs.aggregate(total=Sum("quantity")).get("total") or 0
    )
    sender_label = _user_label(triggered_by)

    msg = render_printing_job_production_completed_markdown(
        printing_order_identifier=str(printing_order_identifier),
        printing_job_id=str(job.id),
        product_name=str(product_name),
        unshipped_sales_items_count=str(unshipped_sales_items_count),
        unshipped_sales_items_quantity=str(unshipped_sales_items_quantity),
        sender_label=str(sender_label),
    )

    if dry_run:
        return {
            "dry_run": True,
            "message": msg,
            "printing_job_id": job.id,
            "printing_order_identifier": str(printing_order_identifier),
            "product_name": str(product_name),
            "unshipped_sales_items_count": unshipped_sales_items_count,
            "unshipped_sales_items_quantity": str(unshipped_sales_items_quantity),
            "sender_label": str(sender_label),
        }

    resp = send_wecom_webhook_message(
        content=msg,
        msgtype="markdown",
        key=key,
        timeout_seconds=timeout_seconds,
    )
    return {
        "dry_run": False,
        "message": msg,
        "printing_job_id": job.id,
        "printing_order_identifier": str(printing_order_identifier),
        "product_name": str(product_name),
        "unshipped_sales_items_count": unshipped_sales_items_count,
        "unshipped_sales_items_quantity": str(unshipped_sales_items_quantity),
        "sender_label": str(sender_label),
        "wecom": resp.raw,
        "ok": resp.ok,
        "errcode": resp.errcode,
        "errmsg": resp.errmsg,
    }
