from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand
from django.db import transaction

from printing import models as printing_models
from stateflow import services as stateflow_services


class Command(BaseCommand):
    help = (
        "修复 printing 相关模型（PrintingJob/PlateOrder）所关联的 BusinessObject 的 "
        "content_type/object_id/name 绑定（用于历史数据回填与一致性修复）。"
    )

    def add_arguments(self, parser):
        parser.add_argument(
            '--dry-run',
            action='store_true',
            help='只输出统计，不写入数据库',
        )
        parser.add_argument(
            '--limit',
            type=int,
            default=None,
            help='最多处理多少条记录（用于分批回填）',
        )
        parser.add_argument(
            '--only',
            choices=['printingjob', 'plateorder', 'all'],
            default='all',
            help='仅修复指定类型（默认 all）',
        )

    def handle(self, *args, **options):
        dry_run: bool = options['dry_run']
        limit: int | None = options['limit']
        only: str = options['only']

        # 提前确保 ContentType 可用（也用于输出校验信息）
        ct_job = ContentType.objects.get_for_model(printing_models.PrintingJob)
        ct_po = ContentType.objects.get_for_model(printing_models.PlateOrder)

        self.stdout.write(f"dry_run={dry_run} only={only} limit={limit}")
        self.stdout.write(f"ContentType: PrintingJob={ct_job.id}, PlateOrder={ct_po.id}")

        stats = {
            'printingjob_total': 0,
            'printingjob_updated': 0,
            'plateorder_total': 0,
            'plateorder_updated': 0,
        }

        def _iter_qs(qs):
            if limit:
                return qs.order_by('id')[:limit]
            return qs.order_by('id')

        # 用事务包住，避免部分更新（dry-run 仍使用事务，最后标记回滚）
        with transaction.atomic():
            if only in ('printingjob', 'all'):
                qs = (
                    printing_models.PrintingJob.objects
                    .select_related('business_object')
                    .filter(business_object__isnull=False)
                )
                for job in _iter_qs(qs):
                    stats['printingjob_total'] += 1
                    bo = job.business_object
                    should_fix = (
                        bo.content_type_id != ct_job.id
                        or bo.object_id != job.id
                        or not (bo.name or '').strip()
                    )
                    if not should_fix:
                        continue

                    if dry_run:
                        stats['printingjob_updated'] += 1
                        continue

                    if stateflow_services.ensure_business_object_bound_to_instance(
                        bo,
                        job,
                        default_name=f"PrintingJob-{job.id}",
                    ):
                        stats['printingjob_updated'] += 1

            if only in ('plateorder', 'all'):
                qs = (
                    printing_models.PlateOrder.objects
                    .select_related('business_object')
                    .filter(business_object__isnull=False)
                )
                for po in _iter_qs(qs):
                    stats['plateorder_total'] += 1
                    bo = po.business_object
                    should_fix = (
                        bo.content_type_id != ct_po.id
                        or bo.object_id != po.id
                        or not (bo.name or '').strip()
                    )
                    if not should_fix:
                        continue

                    if dry_run:
                        stats['plateorder_updated'] += 1
                        continue

                    if stateflow_services.ensure_business_object_bound_to_instance(
                        bo,
                        po,
                        default_name=f"PlateOrder-{po.id}",
                    ):
                        stats['plateorder_updated'] += 1

            if dry_run:
                # dry-run：显式回滚（即便未来误加了写逻辑，也不会落库）
                transaction.set_rollback(True)

        self.stdout.write(self.style.SUCCESS("Done."))
        for k in sorted(stats.keys()):
            self.stdout.write(f"{k}={stats[k]}")


