"""
Printing 模块信号处理函数

监听 stateflow 信号，在流程完成时执行业务逻辑。
"""

import logging
from decimal import Decimal, InvalidOperation
from django.conf import settings
from django.db import transaction
from django.utils import timezone

logger = logging.getLogger(__name__)


def on_printing_job_process_completed(sender, **kwargs):
    """
    PrintingJob 流程完成时的处理
    
    当 PrintingJob 的工艺流程全部完成时，自动创建 SalesItem（销售品）。
    数量和单位从指定的流程节点参数中获取（通过 settings 配置）。
    
    配置项：
        AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER: 是否启用自动创建销售品（默认 True）
        PRINTING_SALES_ITEM_SOURCE_STATE_ID: 指定从哪个 State 获取参数
        PRINTING_SALES_ITEM_QUANTITY_KEY: 数量参数的 key
        PRINTING_SALES_ITEM_UNIT_KEY: 单位参数的 key
    
    Args:
        sender: PrintingJob 类
        content_object: PrintingJob 实例
        business_object: BusinessObject 实例
        last_completed_by: 最后步骤操作人
        其他参数见 stateflow.signals.process_completed
    """
    # 检查是否启用自动创建销售品
    if not getattr(settings, 'AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER', True):
        logger.debug('[printing.handlers] AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER=False，跳过销售品创建')
        return
    
    from shipment.models import SalesItem, UnitChoices
    
    logger.info(
        f'[printing.handlers] 收到 process_completed 信号: '
        f'sender={sender}, kwargs keys={list(kwargs.keys())}'
    )
    
    content_object = kwargs.get('content_object')
    business_object = kwargs.get('business_object')
    last_completed_by = kwargs.get('last_completed_by')
    
    if content_object is None or business_object is None:
        logger.warning('process_completed 信号缺少 content_object 或 business_object')
        return
    
    printing_job = content_object
    logger.info(f'[printing.handlers] 处理 PrintingJob #{printing_job.id}')
    
    # 从 settings 获取配置
    source_state_id = getattr(settings, 'PRINTING_SALES_ITEM_SOURCE_STATE_ID', None)
    quantity_key = getattr(settings, 'PRINTING_SALES_ITEM_QUANTITY_KEY', '米数')
    
    if source_state_id is None:
        logger.debug(
            f'PrintingJob #{printing_job.id} 流程完成，'
            f'但 PRINTING_SALES_ITEM_SOURCE_STATE_ID 未配置，跳过销售品创建'
        )
        return
    
    # 从 business_object 的状态流转记录中找到指定 state_id 的记录
    state_log = business_object.state_logs.filter(
        state_id=source_state_id,
        is_cancelled=False
    ).first()
    
    if state_log is None:
        logger.warning(
            f'PrintingJob #{printing_job.id} 流程完成，'
            f'但未找到 state_id={source_state_id} 的已完成记录，跳过销售品创建'
        )
        return
    
    # 获取参数汇总
    params = state_log.get_all_parameters_summary()
    
    # 获取数量
    quantity_raw = params.get(quantity_key)
    if quantity_raw is None:
        logger.warning(
            f'PrintingJob #{printing_job.id} 流程完成，'
            f'但 state_id={source_state_id} 的参数中缺少 {quantity_key}，跳过销售品创建'
        )
        return
    
    # 转换数量为 Decimal
    try:
        quantity = Decimal(str(quantity_raw))
    except (InvalidOperation, ValueError, TypeError) as e:
        logger.warning(
            f'PrintingJob #{printing_job.id} 流程完成，'
            f'但 {quantity_key}={quantity_raw} 无法转换为数字: {e}，跳过销售品创建'
        )
        return
    
    # 单位固定为"米"
    sales_unit = UnitChoices.METER
    
    # 获取产品名称
    product_name = printing_job.product.name if printing_job.product else '未知产品'
    
    # 获取客户ID（从主订单获取）
    customer_id = None
    if printing_job.printing_order and printing_job.printing_order.customer:
        customer_id = printing_job.printing_order.customer_id
    
    try:
        with transaction.atomic():
            # SalesItem.merchant 不允许为空，优先取 printing_job.merchant
            sales_merchant = getattr(printing_job, 'merchant', None)
            if not sales_merchant and getattr(printing_job, 'printing_order', None):
                sales_merchant = getattr(printing_job.printing_order, 'merchant', None)
            if not sales_merchant and last_completed_by and hasattr(last_completed_by, 'employee'):
                sales_merchant = getattr(last_completed_by.employee, 'merchant', None)
            if not sales_merchant:
                logger.warning(
                    f'PrintingJob #{printing_job.id} 流程完成，'
                    f'但无法确定 merchant，跳过销售品创建'
                )
                return

            sales_item = SalesItem.objects.create(
                shipment=None,  # 暂不关联出货单，待后续分配
                merchant=sales_merchant,
                name=product_name,
                quantity=quantity,
                unit=sales_unit,
                created_by=last_completed_by,
                printing_job_id=printing_job.id,
                customer_id=customer_id,
            )
            
            logger.info(
                f'PrintingJob #{printing_job.id} 流程完成，'
                f'已创建销售品 SalesItem #{sales_item.id}: '
                f'{product_name} x {quantity} {sales_item.get_unit_display()}'
            )
            
    except Exception as e:
        logger.error(
            f'PrintingJob #{printing_job.id} 流程完成后创建销售品失败: {e}',
            exc_info=True
        )


def on_printing_job_state_advanced(sender, **kwargs):
    """
    PrintingJob 每次状态推进时的处理（监听 stateflow.signals.state_advanced）。

    需求：
    - 仅监听 PrintingJob
    - 在事务提交后发送企业微信机器人通知（markdown）
    - 消息包含：
      - PrintingOrder.id
      - PrintingJob.id
      - 被推进状态名 state.name
      - 推进时间（state_log.completed_at）
    """
    # 测试环境默认关闭，避免单测出网/刷屏
    if not getattr(settings, 'PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED', True):
        return
    if getattr(settings, 'TESTING', False):
        return

    content_object = kwargs.get('content_object')
    state = kwargs.get('state')
    state_log = kwargs.get('state_log')
    if content_object is None or state is None or state_log is None:
        logger.warning('[printing.handlers] state_advanced 信号缺少关键参数，跳过通知')
        return

    printing_job = content_object
    printing_job_id = getattr(printing_job, 'id', None)
    printing_order = getattr(printing_job, 'printing_order', None)
    printing_order_id = getattr(printing_order, 'id', None)

    state_name = getattr(state, 'name', None) or str(state)
    advanced_at_dt = getattr(state_log, 'completed_at', None) or getattr(state_log, 'created_at', None)
    advanced_at = (
        timezone.localtime(advanced_at_dt).strftime('%Y-%m-%d %H:%M:%S')
        if advanced_at_dt is not None
        else timezone.localtime(timezone.now()).strftime('%Y-%m-%d %H:%M:%S')
    )

    sender_label = None
    completed_by = kwargs.get('completed_by')
    if completed_by:
        emp = getattr(completed_by, 'employee', None)
        sender_label = getattr(emp, 'name', None) if emp is not None else None
        sender_label = sender_label or getattr(completed_by, 'username', None) or '系统自动发送'
    else:
        sender_label = '系统自动发送'

    # 工序参数：取该 state_log 的最新汇总
    try:
        params = state_log.get_all_parameters_summary(include_cancelled=False) if state_log else {}
    except Exception:
        logger.exception('[printing.handlers] 读取工序参数失败，降级为空')
        params = {}

    try:
        from printing.services import (
            build_printing_job_followup_url,
            render_printing_job_state_markdown,
            render_process_params_markdown,
        )
        followup_url = build_printing_job_followup_url(printing_order_id=printing_order_id)
        process_params_markdown = render_process_params_markdown(params=params)
        message = render_printing_job_state_markdown(
            printing_order_id=str(printing_order_id) if printing_order_id is not None else '-',
            printing_job_id=str(printing_job_id) if printing_job_id is not None else '-',
            state_name=str(state_name),
            advanced_at=str(advanced_at),
            sender_label=str(sender_label),
            followup_url=str(followup_url),
            process_params_markdown=str(process_params_markdown),
        )
    except Exception:
        logger.exception('[printing.handlers] 渲染企业微信消息失败，跳过通知')
        return

    def _send_wecom():
        try:
            from api_v1.utils.wecom_webhook import send_wecom_webhook_message
            resp = send_wecom_webhook_message(content=message, msgtype='markdown')
            if not resp.ok:
                logger.warning(
                    '[printing.handlers] WeCom webhook 返回失败：errcode=%s, errmsg=%s, raw=%s',
                    resp.errcode, resp.errmsg, resp.raw
                )
        except Exception:
            logger.exception('[printing.handlers] 发送 WeCom webhook 失败（已忽略，不影响主流程）')

    # 在事务提交后再发送，避免事务回滚但通知已发出
    transaction.on_commit(_send_wecom)


def on_printing_order_created(sender, **kwargs):
    """
    PrintingOrder 创建时的处理（领域 signal：printing.signals.printing_order_created）。

    需求：
    - 在事务提交后发送企业微信机器人通知（markdown）
    - 消息字段（中文）：
      - 印染订单ID / human_id
      - 创建时间
    - 发送者（优先 created_by.employee.name / created_by.username）
    - 客户、面料、出货日期（可选字段，缺省展示为 '-'）
    """
    # 测试环境默认关闭，避免单测出网/刷屏
    if not getattr(settings, "PRINTING_ORDER_CREATED_WECOM_NOTIFY_ENABLED", True):
        return
    if getattr(settings, "TESTING", False):
        return

    order = kwargs.get("instance")
    created_by = kwargs.get("created_by")
    if order is None:
        logger.warning("[printing.handlers] printing_order_created 信号缺少 instance，跳过通知")
        return

    try:
        from printing.services import render_printing_order_created_markdown

        created_at_dt = getattr(order, "created_at", None)
        created_at = (
            timezone.localtime(created_at_dt).strftime("%Y-%m-%d %H:%M:%S")
            if created_at_dt is not None
            else timezone.localtime(timezone.now()).strftime("%Y-%m-%d %H:%M:%S")
        )

        emp = getattr(created_by, "employee", None) if created_by else None
        sender_label = getattr(emp, "name", None) if emp is not None else None
        sender_label = sender_label or getattr(created_by, "username", None) if created_by else None
        sender_label = sender_label or "系统自动发送"

        customer_name = None
        try:
            customer = getattr(order, "customer", None)
            customer_name = getattr(customer, "name", None) if customer else None
        except Exception:
            customer_name = None

        outgoing_dt = getattr(order, "outgoing_date", None)
        outgoing_date = (
            timezone.localtime(outgoing_dt).strftime("%Y-%m-%d %H:%M:%S")
            if outgoing_dt is not None
            else "-"
        )
        order_id = str(getattr(order, "id", "-") or "-")

        message = render_printing_order_created_markdown(
            printing_order_id=order_id,
            printing_order_human_id=str(getattr(order, "human_id", "-") or "-"),
            created_at=str(created_at),
            sender_label=str(sender_label),
            customer_name=str(customer_name or "-"),
            fabric=str(getattr(order, "fabric", "-") or "-"),
            outgoing_date=str(outgoing_date),
        )
    except Exception:
        logger.exception("[printing.handlers] 渲染企业微信消息失败，跳过通知")
        return

    def _send_wecom():
        try:
            from api_v1.utils.wecom_webhook import send_wecom_webhook_message

            resp = send_wecom_webhook_message(content=message, msgtype="markdown")
            if not resp.ok:
                logger.warning(
                    "[printing.handlers] WeCom webhook 返回失败：errcode=%s, errmsg=%s, raw=%s",
                    resp.errcode,
                    resp.errmsg,
                    resp.raw,
                )
        except Exception:
            logger.exception("[printing.handlers] 发送 WeCom webhook 失败（已忽略，不影响主流程）")

        if getattr(settings, "PRINTING_ORDER_CREATED_SPEECH_ENABLED", False):
            try:
                from flower.utils import play_speech

                play_speech(text=f"生产订单 {order_id} 已创建")
            except Exception:
                logger.exception("[printing.handlers] 发送语音播报失败（已忽略，不影响主流程）")

    # 在事务提交后再发送，避免事务回滚但通知已发出
    transaction.on_commit(_send_wecom)


def on_printing_job_production_completed(sender, **kwargs):
    """
    PrintingJob 被显式标记为完成生产后的处理。

    当前通过 Celery task 异步发送企业微信通知，避免阻塞主流程。
    """
    if not getattr(settings, "PRINTING_JOB_PRODUCTION_COMPLETED_WECOM_NOTIFY_ENABLED", True):
        return
    if getattr(settings, "TESTING", False):
        return

    job = kwargs.get("instance")
    triggered_by = kwargs.get("triggered_by")
    if job is None:
        logger.warning(
            "[printing.handlers] printing_job_production_completed 信号缺少 instance，跳过通知"
        )
        return

    logger.info(
        "[printing.handlers] 收到 printing_job_production_completed 信号: sender=%s, job_id=%s",
        sender,
        getattr(job, "id", None),
    )

    def _enqueue_task():
        try:
            from printing.tasks import notify_printing_job_production_completed_wecom

            notify_printing_job_production_completed_wecom.delay(
                printing_job_id=job.id,
                triggered_by_id=getattr(triggered_by, "id", None),
            )
        except Exception:
            logger.exception(
                "[printing.handlers] 投递 notify_printing_job_production_completed_wecom task 失败（已忽略，不影响主流程）"
            )

    transaction.on_commit(_enqueue_task)
