from decimal import Decimal

from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.db import models
from flower.common import ModelBase
from basic_info import models as basic_models
from stateflow import models as stateflow_models


class PlateOrder(ModelBase):
    """开版管理订单"""
    
    # 商户关联（多租户）
    merchant = models.ForeignKey(
        basic_models.Merchant,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='plate_orders',
        verbose_name='商户',
        help_text='所属商户，可空以兼容历史数据'
    )
    
    # 自动编号相关
    design_code = models.CharField(max_length=50, blank=True, null=True, verbose_name='设计编号')
    original_id = models.PositiveBigIntegerField(
        null=True,
        blank=True,
        verbose_name='克隆来源订单ID',
        help_text='前端克隆概念：记录本订单由哪个订单复制而来（无外键约束）',
    )
    
    # 版相关信息
    plate_type = models.CharField(max_length=20, blank=True, null=True, verbose_name='起版情况')  # 首版/复版等
    plate_date = models.DateTimeField(null=True, blank=True, verbose_name='下版时间')
    plate_method = models.CharField(max_length=50, blank=True, null=True, verbose_name='开版方式')
    plate_image = models.JSONField(
        default=list,
        blank=True,
        verbose_name='开版图',
        help_text='存储多个开版图片引用信息，例如 [{"file_id": 1, "name": "封面", "path": "/media/xxx"}]'
    )
    image_name = models.TextField(blank=True, null=True, verbose_name='图片名称')
    plate_notes = models.TextField(blank=True, null=True, verbose_name='打版注意事项')
    reprint_reason = models.TextField(blank=True, null=True, verbose_name='复版原因')
    
    # 状态和进程
    # development_status = models.CharField(max_length=20, blank=True, null=True, verbose_name='开发进程')  # 未打印/待画图等
    urgency_level = models.CharField(max_length=20, default='正常', verbose_name='紧急程度')  # 正常/加急
    
    # 人员关联
    salesperson = models.ForeignKey(
        basic_models.Employee,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='plate_orders_as_salesperson',
        verbose_name='销售员'
    )
    merchandiser = models.ForeignKey(
        basic_models.Employee,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='plate_orders_as_merchandiser',
        verbose_name='跟单员'
    )
    designer = models.ForeignKey(
        basic_models.Employee,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='plate_orders_as_designer',
        verbose_name='设计师'
    )
    
    # 客户和地址信息
    customer = models.ForeignKey(
        basic_models.Customer,
        on_delete=models.PROTECT,
        related_name='plate_orders',
        verbose_name='客户',
    )
    area = models.CharField(max_length=255, blank=True, null=True, verbose_name='区域')
    default_address = models.CharField(max_length=500, blank=True, null=True, verbose_name='默认地址')
    
    # 质量评级
    is_mark_frame = models.BooleanField(default=False, verbose_name='是否套唛架')
    drawing_rating = models.CharField(max_length=20, blank=True, null=True, verbose_name='画图评级')
    color_matching_rating = models.CharField(max_length=20, blank=True, null=True, verbose_name='调色评级')
    sample_rating = models.CharField(max_length=20, blank=True, null=True, verbose_name='套样评级')
    difficulty_rating = models.CharField(max_length=20, blank=True, null=True, verbose_name='难度评级')
    
    # 时间相关
    required_completion_date = models.DateTimeField(null=True, blank=True, verbose_name='要求完成时间')
    completion_date = models.DateTimeField(null=True, blank=True, verbose_name='完成时间')
    
    # 产品信息
    fabric = models.CharField(max_length=100, blank=True, null=True, verbose_name='布料')
    fabric_source = models.CharField(max_length=100, blank=True, null=True, verbose_name='布料来源')
    width = models.CharField(max_length=50, blank=True, null=True, verbose_name='幅宽')
    style_name = models.CharField(max_length=100, blank=True, null=True, verbose_name='款号名称')
    
    # 生产方式
    production_method = models.CharField(max_length=50, blank=True, null=True, verbose_name='做货方式')
    
    # 样品相关
    sample_meter = models.CharField(max_length=100, blank=True, null=True, verbose_name='米样')
    required_sample_meters = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name='客户要求米样米数'
    )
    
    # 审批和订单状态
    approval_result = models.CharField(max_length=50, blank=True, null=True, verbose_name='审批结果')
    is_ordered = models.BooleanField(default=False, verbose_name='是否已下单')
    is_invalid = models.BooleanField(default=False, verbose_name='是否作废')
    customer_feedback = models.TextField(blank=True, null=True, verbose_name='客户修改意见')
    print_count = models.PositiveIntegerField(default=0, verbose_name='打印次数')
    
    # 流程管理
    process = models.IntegerField(default=settings.PLATE_ORDER_DEFAULT_PROCESS_ID, verbose_name='关联流程')
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='created_plate_orders',
        verbose_name='创建人',
    )
    business_object = models.OneToOneField(
        stateflow_models.BusinessObject,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='plate_order',
        verbose_name='流程实例',
    )
    
    def __str__(self):
        return f'PlateOrder-{self.id}'
    
    def save(self, *args, **kwargs):
        """保存时自动创建 BusinessObject"""
        # 先保存以获取 ID（如果是新建）
        is_new = self.pk is None
        update_fields = kwargs.get('update_fields')
        super().save(*args, **kwargs)
        
        should_auto_create = (
            self.process
            and not self.business_object
            and (is_new or update_fields is None or 'process' in (update_fields or []))
        )

        # 如果有 process 且没有 business_object，则自动创建
        if should_auto_create:
            try:
                from stateflow.models import Process
                process_obj = Process.objects.get(id=self.process)
                
                # 创建 BusinessObject
                business_object = stateflow_models.BusinessObject.objects.create(
                    name=f"PlateOrder-{self.id}",
                    process=process_obj,
                    description=f"开版订单 {self.id} 的流程实例",
                    content_type=ContentType.objects.get_for_model(PlateOrder),
                    object_id=self.id,
                )
                self.business_object = business_object
                # 再次保存以更新 business_object 字段
                super().save(update_fields=['business_object'])
            except Process.DoesNotExist:
                # 如果流程不存在，忽略错误
                pass
    
    class Meta:
        verbose_name = '开版订单'
        verbose_name_plural = '开版订单'
        ordering = ['-created_at']
        indexes = [
            models.Index(
                fields=['merchant', 'plate_date'],
                name='idx_plateord_merch_pltdt',
            ),
        ]
        permissions = [
            ('can_invalidate_plateorder', '可以作废开版订单'),
            ('can_activate_plateorder', '可以恢复开版订单'),
            ('view_all_plateorders', '查看所有开版订单（突破客户可见性限制）'),
        ]
    
    @property
    def status(self) -> str:
        """
        返回当前状态名称
        
        规则：
        - current_state 为 None：返回"已完成"
        - 否则：返回 current_state 的名称
        
        注意：废除了"未开始"的概念，直接显示节点名称
        """
        from stateflow.services import get_display_status
        return get_display_status(self.business_object)
    
    @property
    def last_completed_state(self) -> str:
        """
        返回最后一个已完成节点的名称，用于详情展示
        """
        if not self.business_object:
            return ''
        from stateflow.services import get_last_completed_state
        last_state = get_last_completed_state(self.business_object)
        return last_state.name if last_state else ''
    
    @property
    def status_id(self):
        """返回当前状态ID（下一个待执行的状态ID）"""
        if not self.business_object:
            return None
        current_state = self.business_object.get_current_state()
        return current_state.id if current_state else None
    
    @property
    def is_completed(self) -> bool:
        """判断是否完成"""
        if not self.business_object:
            return False
        
        # 检查流程是否完成
        from stateflow.services import get_overall_status
        return get_overall_status(self.business_object) == 'completed'
    
    @property
    def has_started(self) -> bool:
        """判断是否已开始（有未撤销的状态记录）"""
        if not self.business_object:
            return False
        
        # 只检查未撤销的记录
        from stateflow.models import StateFlowRecord
        has_records = StateFlowRecord.objects.filter(
            business_object=self.business_object,
            is_cancelled=False
        ).exists()
        
        return has_records
    
    @property
    def progress_percentage(self) -> float:
        """计算进度百分比"""
        if not self.business_object:
            return 0.0
        
        return self.business_object.get_progress_percentage()


class PlateOrderTiiaUploadFailure(ModelBase):
    """
    PlateOrder 图片上传腾讯云图库失败记录（用于定时任务/人工重试追踪）。

    设计目标：最小可用——记录“哪天跑的任务 + 哪个 plate_order_id + 失败详情/次数”。
    """
    run_date = models.DateField(
        verbose_name='任务日期',
        help_text='以任务处理的日期为准（通常为“昨天”）',
    )
    plate_order_id = models.PositiveBigIntegerField(
        verbose_name='开版订单ID',
        db_index=True,
        help_text='PlateOrder.id（不使用外键，避免历史数据/删除带来的约束问题）',
    )
    error = models.TextField(
        blank=True,
        default='',
        verbose_name='错误摘要',
    )
    details = models.JSONField(
        default=list,
        blank=True,
        verbose_name='错误详情',
        help_text='通常存储 upload_plate_order_images_to_tencent_tiia 返回的失败条目列表',
    )
    attempts = models.PositiveIntegerField(
        default=0,
        verbose_name='尝试次数',
    )
    last_attempt_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='最后尝试时间',
    )

    class Meta:
        verbose_name = '开版订单图片上传失败记录'
        verbose_name_plural = '开版订单图片上传失败记录'
        ordering = ['-created_at']
        constraints = [
            models.UniqueConstraint(
                fields=['run_date', 'plate_order_id'],
                name='uniq_plateorder_tiia_fail_run_date_po',
            )
        ]


class PrintingOrder(ModelBase):
    """PrintingOrder model representing a printing order."""
    
    # 商户关联（多租户）
    merchant = models.ForeignKey(
        basic_models.Merchant,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='printing_orders',
        verbose_name='商户',
        help_text='所属商户，可空以兼容历史数据'
    )
    
    customer = models.ForeignKey(
        basic_models.Customer, 
        on_delete=models.PROTECT, 
        related_name='printing_orders', 
        verbose_name='客户',
    )
    fabric = models.CharField(max_length=100, verbose_name='面料')
    width = models.CharField(max_length=100, verbose_name='幅宽')
    is_urgent = models.BooleanField(default=False, verbose_name='紧急')
    area = models.CharField(max_length=100, null=True, blank=True, verbose_name='地区')
    address = models.CharField(max_length=200, null=True, blank=True, verbose_name='地址')
    fabric_source = models.CharField(max_length=100, null=True, blank=True, verbose_name='布料来源')
    is_fabric_received = models.BooleanField(default=False, verbose_name='布料是否已收')
    craft = models.CharField(max_length=100, null=True, blank=True, verbose_name='工艺')
    description = models.TextField(blank=True, null=True, verbose_name='订单描述')
    outgoing_date = models.DateTimeField(null=True, blank=True, verbose_name='出货日期')
    curve = models.CharField(max_length=100, blank=True, null=True, verbose_name='曲线')
    new_curve = models.CharField(max_length=100, blank=True, null=True, verbose_name='新加曲线')
    position = models.TextField(blank=True, null=True, verbose_name='位置')
    printing_warn = models.TextField(blank=True, null=True, verbose_name='打印注意事项')
    rolling_warn = models.TextField(blank=True, null=True, verbose_name='滚筒注意事项')
    production_warn = models.TextField(blank=True, null=True, verbose_name='生产注意事项')
    print_count = models.PositiveIntegerField(default=0, verbose_name='打印次数')
    is_invalid = models.BooleanField(default=False, verbose_name='是否作废')
    process = models.ForeignKey(
        stateflow_models.Process,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='printing_orders',
        verbose_name='印染流程',
    )
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='printing_orders',
        verbose_name='创建人',
    )
    external_order_id = models.CharField(
        max_length=100,
        blank=True,
        null=True,
        db_index=True,
        verbose_name='外部订单编号',
    )
    external_customer_id = models.CharField(
        max_length=100,
        blank=True,
        null=True,
        verbose_name='外部客户ID',
    )
    external_customer_name = models.CharField(
        max_length=100,
        blank=True,
        null=True,
        verbose_name='外部客户名',
    )
    external_employee_name = models.CharField(
        max_length=100,
        blank=True,
        null=True,
        verbose_name='外部员工名',
    )
    external_raw = models.JSONField(
        default=dict,
        blank=True,
        verbose_name='外部原始数据',
        help_text='保存外部 records 聚合后的 order 级原始数据快照',
    )

    def __str__(self):
        return self.human_id

    class Meta:
        verbose_name = '印染订单'
        verbose_name_plural = '印染订单'
        permissions = [
            ('can_invalidate_printingorder', '可以作废印染订单'),
            ('can_activate_printingorder', '可以恢复印染订单'),
            ('view_all_printingorders', '查看所有印染订单（突破客户可见性限制）'),
        ]

    @property
    def human_id(self) -> str:
        if self.id is None or self.created_at is None:
            return ""
        return f"{self.created_at.year}{self.created_at.month:02d}{self.created_at.day:02d}{self.id:06d}"

    def can_change_process(self) -> bool:
        """检查是否可以修改流程（所有job都未开始）"""
        return not any(job.has_started for job in self.printing_jobs.all())

    @property
    def progress(self) -> int:
        """计算订单完成进度百分比（已完成的任务数 / 总任务数）"""
        jobs = self.printing_jobs.all()
        if not jobs.exists():
            return 0
        
        completed_count = sum(1 for job in jobs if job.is_completed)
        return int((completed_count / jobs.count()) * 100)


class PrintingJobWorkStateEnum(models.IntegerChoices):
    PRODUCING = 0, '生产中'
    WAITING_FOR_DELIVERY = 1, '待送货'
    WAITING_FOR_INVOICE = 2, '待开单'
    FINISHED = 3, '已完结'


class PrintingJob(ModelBase):
    """PrintingJob model representing a printing job associated with an order."""
    
    # 商户关联（多租户）
    merchant = models.ForeignKey(
        basic_models.Merchant,
        on_delete=models.PROTECT,
        null=True,
        blank=True,
        related_name='printing_jobs',
        verbose_name='商户',
        help_text='所属商户，可空以兼容历史数据'
    )
    
    printing_order = models.ForeignKey(
        PrintingOrder, 
        on_delete=models.CASCADE, 
        related_name='printing_jobs', 
        verbose_name='主订单',
    )
    product = models.ForeignKey(
        basic_models.Product, 
        on_delete=models.PROTECT, 
        related_name='printing_jobs', 
        verbose_name='产品',
    )
    work_state = models.IntegerField(
        choices=PrintingJobWorkStateEnum.choices,
        default=PrintingJobWorkStateEnum.PRODUCING,
        verbose_name='业务进展',
    )
    is_production_completed = models.BooleanField(
        default=False,
        verbose_name='是否完成生产',
        help_text='独立于流程计算状态的生产完成标记',
    )
    quantity = models.PositiveIntegerField(verbose_name='数量')
    unit = models.CharField(max_length=50, verbose_name='单位')
    size = models.CharField(max_length=100, null=True, blank=True, verbose_name='一段尺寸')
    pieces = models.PositiveIntegerField(null=True, blank=True, verbose_name='件数')
    description = models.TextField(blank=True, null=True, verbose_name='备注')
    original_id = models.PositiveBigIntegerField(
        null=True,
        blank=True,
        verbose_name='克隆来源任务ID',
        help_text='前端克隆概念：记录本任务由哪个任务复制而来（无外键约束）',
    )
    sub_id = models.IntegerField(
        null=True,
        blank=True,
        verbose_name='子编号',
    )
    business_object = models.OneToOneField(
        stateflow_models.BusinessObject,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='printing_job',
        verbose_name='流程实例',
    )
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='printing_jobs',
        verbose_name='创建人',
    )
    external_product_name = models.CharField(
        max_length=200,
        blank=True,
        null=True,
        verbose_name='外部产品名',
    )
    external_raw = models.JSONField(
        default=dict,
        blank=True,
        verbose_name='外部原始数据',
        help_text='保存外部 record 的完整原始数据',
    )

    def __str__(self):
        return self.printing_order.human_id

    @property
    def billed_quantity(self) -> Decimal:
        """
        开单数量：所有关联的非作废销售单明细数量之和
        """
        from business.models import SalesOrderStatusEnum

        total = self.sales_order_items.exclude(
            sales_order__status=SalesOrderStatusEnum.CANCELLED,
        ).aggregate(total=models.Sum('quantity')).get('total')
        return total or Decimal('0')

    @property
    def is_sales_order_bound(self) -> bool:
        """是否已被非作废销售单明细绑定。"""
        from business.models import SalesOrderStatusEnum

        cached = getattr(self, '_is_sales_order_bound_cache', None)
        if cached is not None:
            return bool(cached)
        return self.sales_order_items.exclude(
            sales_order__status=SalesOrderStatusEnum.CANCELLED,
        ).exists()

    @property
    def status(self) -> str:
        """
        返回当前状态名称
        
        规则：
        - current_state 为 None：返回"已完成"
        - 否则：返回 current_state 的名称
        
        注意：废除了"未开始"的概念，直接显示节点名称
        """
        from stateflow.services import get_display_status
        return get_display_status(self.business_object)

    @property
    def status_id(self):
        """返回当前状态ID（下一个待执行的状态ID）"""
        if not self.business_object:
            return None
        current_state = self.business_object.get_current_state()
        return current_state.id if current_state else None

    @property
    def is_completed(self) -> bool:
        """判断是否完成（所有流程节点都已完成）"""
        if not self.business_object or not self.printing_order.process:
            return False
        
        # 获取流程的所有节点
        process_nodes = self.printing_order.process.process_nodes.all()
        total_nodes = process_nodes.count()
        
        if total_nodes == 0:
            return False
        
        # 检查已完成的节点数
        completed_count = self.business_object.state_logs.filter(is_cancelled=False).count()
        
        # 所有节点都完成了才算完成
        return completed_count >= total_nodes

    @property
    def has_started(self) -> bool:
        """判断是否已开始（有未撤销的状态记录）"""
        if not self.business_object:
            return False
        
        # 只检查未撤销的记录
        from stateflow.models import StateFlowRecord
        has_records = StateFlowRecord.objects.filter(
            business_object=self.business_object,
            is_cancelled=False
        ).exists()
        
        return has_records

    @property
    def progress_percentage(self) -> float:
        """计算进度百分比"""
        if not self.business_object:
            return 0.0
        
        return self.business_object.get_progress_percentage()

    @property
    def last_completed_state(self) -> str:
        """返回最后一个已完成节点的名称，用于详情展示"""
        if not self.business_object:
            return ''
        from stateflow.services import get_last_completed_state
        last_state = get_last_completed_state(self.business_object)
        return last_state.name if last_state else ''

    class Meta:
        verbose_name = '印染款式明细'
        verbose_name_plural = '印染款式明细'


class PrintingJobBatchAdvanceRecord(ModelBase):
    """
    印染任务批量操作记录（审计）

    记录一次"对多个 PrintingJob 用同一组参数操作同一步流程节点"的行为：
    - created_by/created_at：谁在何时做了批量操作
    - parameters：本次操作提交的工艺参数（JSON）
    - state：本次操作的流程节点
    - printing_jobs：本次批量操作涉及的所有明细
    - only_parameters：操作类型
      - False（默认）：批量推进状态
      - True：仅批量补充工艺参数（不推进状态）
    """

    printing_order = models.ForeignKey(
        PrintingOrder,
        on_delete=models.PROTECT,
        related_name='batch_advance_records',
        verbose_name='印染订单',
    )
    state = models.ForeignKey(
        stateflow_models.State,
        on_delete=models.PROTECT,
        related_name='printing_job_batch_advance_records',
        verbose_name='操作的流程节点',
    )
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='printing_job_batch_advance_records',
        verbose_name='创建人',
    )
    parameters = models.JSONField(
        default=dict,
        blank=True,
        verbose_name='工艺参数',
        help_text='批量操作时提交的参数',
    )
    printing_jobs = models.ManyToManyField(
        PrintingJob,
        related_name='batch_advance_records',
        verbose_name='印染明细',
        blank=False,
    )
    only_parameters = models.BooleanField(
        default=False,
        verbose_name='仅参数补充',
        help_text='True=仅补充参数（不推进状态），False=批量推进状态',
    )

    class Meta:
        verbose_name = '印染任务批量操作记录'
        verbose_name_plural = '印染任务批量操作记录'


class PrintingOrderExternalSnapshotSyncAudit(ModelBase):
    """
    外部订单快照同步审计记录。

    记录一次“按 external_order_id 触发外部快照覆盖同步”的执行结果：
    - before_snapshot: 同步前本地 PrintingOrder / PrintingJob 快照
    - operator_user / operator_employee: 触发人
    - is_success / failure_reason: 成功或失败及失败原因
    - allow_reset_stateflow: 本次是否允许撤销已有工序
    """

    printing_order = models.ForeignKey(
        PrintingOrder,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='external_snapshot_sync_audits',
        verbose_name='印染订单',
    )
    external_order_id = models.CharField(
        max_length=100,
        db_index=True,
        verbose_name='外部订单编号',
    )
    operator_user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='printing_order_external_snapshot_sync_audits',
        verbose_name='操作者',
    )
    operator_employee = models.ForeignKey(
        basic_models.Employee,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='printing_order_external_snapshot_sync_audits',
        verbose_name='操作员工',
    )
    before_snapshot = models.JSONField(
        default=dict,
        blank=True,
        verbose_name='同步前快照',
    )
    allow_reset_stateflow = models.BooleanField(
        default=False,
        verbose_name='允许撤销工序',
    )
    is_success = models.BooleanField(
        default=False,
        verbose_name='是否成功',
    )
    failure_reason = models.TextField(
        blank=True,
        default='',
        verbose_name='失败原因',
    )

    class Meta:
        verbose_name = '外部订单快照同步审计记录'
        verbose_name_plural = '外部订单快照同步审计记录'
        ordering = ['-created_at', '-id']

    def __str__(self) -> str:
        return f'{self.external_order_id} #{self.id}'
