# -*- coding: utf-8 -*-
"""
把龙先生(lxs)审核版商品目录复制到小溪(xx)。

范围（必须全部满足）：
  - 源俱乐部固定 lxs（name 含「龙先生」）
  - 目标俱乐部固定 xx（name 含「小溪」「小西」或「小汐」）
  - 仅全局 ShangpinLeixing.shenhezhuangtai=2 的类型
  - 仅公共目录 dianpu IS NULL
  - 专区/商品均要求 shenhezhuangtai=2

步骤：
  1) （可选）清空 xx 下上述审核类型的专区+商品（只删 DB，不删 OSS）
  2) 从 lxs 复制同类型专区+商品到 xx（图片复用相对路径；销量归零）
  3) 确保 xx 的 ClubShangpinLeixingConfig 启用这些审核类型（图标可复用源配置）

不碰：正常商品(shenhezhuangtai=1)、其它俱乐部、店铺商品、全局类型表、订单等。

用法:
  python manage.py copy_lxs_shenhe_catalog_to_xx --list
  python manage.py copy_lxs_shenhe_catalog_to_xx
  python manage.py copy_lxs_shenhe_catalog_to_xx --apply --i-confirm=lxs-to-xx
  python manage.py copy_lxs_shenhe_catalog_to_xx --apply --i-confirm=lxs-to-xx --clear-target
"""
from __future__ import annotations

from django.core.management.base import BaseCommand, CommandError
from django.db import transaction

SOURCE_CLUB = 'lxs'
SOURCE_NAME_HINT = '龙先生'
TARGET_CLUB = 'xx'
TARGET_NAME_HINTS = ('小溪', '小西', '小汐')
SHENHE = 2
CONFIRM_TOKEN = 'lxs-to-xx'


class Command(BaseCommand):
    help = '复制龙先生审核专区/商品到小溪(xx)（默认 dry-run）'

    def add_arguments(self, parser):
        parser.add_argument('--apply', action='store_true', help='真正写库')
        parser.add_argument(
            '--i-confirm',
            type=str,
            default='',
            help=f'必须等于 {CONFIRM_TOKEN} 才允许 --apply',
        )
        parser.add_argument(
            '--clear-target',
            action='store_true',
            help='写入前先清空 xx 下对应审核专区/商品（只删 DB）',
        )
        parser.add_argument(
            '--list',
            action='store_true',
            help='只列出审核类型及 lxs/xx 下专区商品数量',
        )

    def handle(self, *args, **options):
        from jituan.models import Club, ClubShangpinLeixingConfig
        from products.models import Shangpin, ShangpinLeixing, ShangpinZhuanqu

        apply = bool(options.get('apply'))
        confirm = (options.get('i_confirm') or '').strip()
        clear_target = bool(options.get('clear_target'))

        src_club = Club.query.filter(club_id=SOURCE_CLUB).first()
        if not src_club:
            raise CommandError(f'源俱乐部 {SOURCE_CLUB} 不存在')
        if SOURCE_NAME_HINT not in (src_club.name or ''):
            raise CommandError(
                f'安全拦截：{SOURCE_CLUB} 的 name={src_club.name!r} 不含「{SOURCE_NAME_HINT}」'
            )

        dst_club = Club.query.filter(club_id=TARGET_CLUB).first()
        if not dst_club:
            raise CommandError(
                f'目标俱乐部 {TARGET_CLUB} 不存在。请先在后台创建小溪俱乐部(club_id=xx)。'
            )
        if not any(h in (dst_club.name or '') for h in TARGET_NAME_HINTS):
            raise CommandError(
                f'安全拦截：{TARGET_CLUB} 的 name={dst_club.name!r} '
                f'不含「{"/".join(TARGET_NAME_HINTS)}」'
            )

        audit_types = list(
            ShangpinLeixing.query.filter(shenhezhuangtai=SHENHE).order_by('id')
        )
        if not audit_types:
            raise CommandError('没有任何审核专用商品类型(shenhezhuangtai=2)')
        if len(audit_types) != 3:
            self.stdout.write(self.style.WARNING(
                f'注意：当前审核类型数量={len(audit_types)}（预期常为 3），将按实际全部处理。'
            ))

        leixing_ids = [lx.id for lx in audit_types]

        def counts(club_id):
            z = ShangpinZhuanqu.query.filter(
                club_id=club_id,
                leixing_id__in=leixing_ids,
                shenhezhuangtai=SHENHE,
                dianpu__isnull=True,
            ).count()
            p = Shangpin.query.filter(
                club_id=club_id,
                leixing_id__in=leixing_ids,
                shenhezhuangtai=SHENHE,
                dianpu__isnull=True,
            ).count()
            return z, p

        def per_type(club_id):
            rows = []
            for lx in audit_types:
                z = ShangpinZhuanqu.query.filter(
                    club_id=club_id,
                    leixing_id=lx.id,
                    shenhezhuangtai=SHENHE,
                    dianpu__isnull=True,
                ).count()
                p = Shangpin.query.filter(
                    club_id=club_id,
                    leixing_id=lx.id,
                    shenhezhuangtai=SHENHE,
                    dianpu__isnull=True,
                ).count()
                rows.append((lx, z, p))
            return rows

        if options.get('list'):
            self.stdout.write(self.style.NOTICE('审核类型及两侧存量：'))
            for lx in audit_types:
                sz, sp = (
                    ShangpinZhuanqu.query.filter(
                        club_id=SOURCE_CLUB, leixing_id=lx.id,
                        shenhezhuangtai=SHENHE, dianpu__isnull=True,
                    ).count(),
                    Shangpin.query.filter(
                        club_id=SOURCE_CLUB, leixing_id=lx.id,
                        shenhezhuangtai=SHENHE, dianpu__isnull=True,
                    ).count(),
                )
                dz, dp = (
                    ShangpinZhuanqu.query.filter(
                        club_id=TARGET_CLUB, leixing_id=lx.id,
                        shenhezhuangtai=SHENHE, dianpu__isnull=True,
                    ).count(),
                    Shangpin.query.filter(
                        club_id=TARGET_CLUB, leixing_id=lx.id,
                        shenhezhuangtai=SHENHE, dianpu__isnull=True,
                    ).count(),
                )
                self.stdout.write(
                    f'  id={lx.id}「{lx.jieshao}」  '
                    f'lxs: zones={sz} products={sp}  |  '
                    f'xx: zones={dz} products={dp}'
                )
            return

        if apply and confirm != CONFIRM_TOKEN:
            raise CommandError(
                f'安全拦截：--apply 必须带 --i-confirm={CONFIRM_TOKEN}\n'
                f'  python manage.py copy_lxs_shenhe_catalog_to_xx '
                f'--apply --i-confirm={CONFIRM_TOKEN}'
            )

        src_z_total, src_p_total = counts(SOURCE_CLUB)
        dst_z_total, dst_p_total = counts(TARGET_CLUB)

        src_zones = list(
            ShangpinZhuanqu.query.filter(
                club_id=SOURCE_CLUB,
                leixing_id__in=leixing_ids,
                shenhezhuangtai=SHENHE,
                dianpu__isnull=True,
            ).order_by('leixing_id', 'paixu', 'id')
        )
        src_products = list(
            Shangpin.query.filter(
                club_id=SOURCE_CLUB,
                leixing_id__in=leixing_ids,
                shenhezhuangtai=SHENHE,
                dianpu__isnull=True,
            ).order_by('leixing_id', 'paixu', 'id')
        )

        src_zone_ids = {z.id for z in src_zones}
        orphan = [p for p in src_products if p.zhuanqu_id not in src_zone_ids]
        if orphan:
            sample = ', '.join(f'{p.id}:{p.biaoqian}' for p in orphan[:5])
            raise CommandError(
                f'源商品有 {len(orphan)} 条专区不在本批审核专区内，已中止。样例: {sample}'
            )

        if src_z_total == 0 and src_p_total == 0:
            raise CommandError('龙先生(lxs)下没有可复制的审核专区/商品')

        mode = 'APPLY' if apply else 'DRY-RUN'
        self.stdout.write(self.style.NOTICE(
            f'\n===== {mode} 小溪审核目录 ← 龙先生 =====\n'
            f'源: {SOURCE_CLUB} ({src_club.name})  '
            f'专区={src_z_total} 商品={src_p_total}\n'
            f'目标: {TARGET_CLUB} ({dst_club.name})  '
            f'现有 专区={dst_z_total} 商品={dst_p_total}\n'
            f'clear_target={clear_target}\n'
            f'审核类型数={len(audit_types)} ids={leixing_ids}\n'
            f'OSS: 不删文件；复制时复用龙先生相对路径（同一 COS 域名拼接）\n'
        ))

        self.stdout.write('—— 分类型存量 ——')
        for lx, sz, sp in per_type(SOURCE_CLUB):
            self.stdout.write(f'  [lxs] id={lx.id}「{lx.jieshao}」 zones={sz} products={sp}')
        for lx, dz, dp in per_type(TARGET_CLUB):
            self.stdout.write(f'  [xx] id={lx.id}「{lx.jieshao}」 zones={dz} products={dp}')

        self.stdout.write('—— 将从 lxs 复制的专区样例 ——')
        for z in src_zones[:40]:
            self.stdout.write(
                f'  zq#{z.id} leixing={z.leixing_id} {z.mingzi!r}'
            )
        if len(src_zones) > 40:
            self.stdout.write(f'  ... 其余 {len(src_zones) - 40} 个省略')

        self.stdout.write('—— 将从 lxs 复制的商品样例 ——')
        for p in src_products[:15]:
            self.stdout.write(
                f'  sp#{p.id} leixing={p.leixing_id} {p.biaoqian!r} ¥{p.jiage}'
            )
        if len(src_products) > 15:
            self.stdout.write(f'  ... 其余 {len(src_products) - 15} 个省略')

        if not apply:
            self.stdout.write(self.style.WARNING(
                '\n以上仅计划：未删库、未写库。确认无误后：\n'
                f'  python manage.py copy_lxs_shenhe_catalog_to_xx '
                f'--apply --i-confirm={CONFIRM_TOKEN}\n'
                f'若目标已有旧审核目录需先清空，再加 --clear-target\n'
            ))
            return

        stats = {
            'deleted_products': 0,
            'deleted_zones': 0,
            'zones_created': 0,
            'products_created': 0,
            'cfg_created': 0,
            'cfg_enabled': 0,
        }

        with transaction.atomic():
            if clear_target:
                n_prod, _ = Shangpin.query.filter(
                    club_id=TARGET_CLUB,
                    leixing_id__in=leixing_ids,
                    shenhezhuangtai=SHENHE,
                    dianpu__isnull=True,
                ).delete()
                n_zone, _ = ShangpinZhuanqu.query.filter(
                    club_id=TARGET_CLUB,
                    leixing_id__in=leixing_ids,
                    shenhezhuangtai=SHENHE,
                    dianpu__isnull=True,
                ).delete()
                stats['deleted_products'] = n_prod
                stats['deleted_zones'] = n_zone

            zone_id_map = {}
            for z in src_zones:
                if z.leixing_id not in leixing_ids:
                    raise CommandError(f'专区 {z.id} 类型 {z.leixing_id} 不在审核列表')
                # 未 clear 时若同名专区已存在则复用，避免重复堆叠
                exist = None
                if not clear_target:
                    exist = ShangpinZhuanqu.query.filter(
                        club_id=TARGET_CLUB,
                        leixing_id=z.leixing_id,
                        mingzi=z.mingzi,
                        shenhezhuangtai=SHENHE,
                        dianpu__isnull=True,
                    ).first()
                if exist:
                    zone_id_map[z.id] = exist.id
                    continue
                row = ShangpinZhuanqu.query.create(
                    mingzi=z.mingzi,
                    leixing_id=z.leixing_id,
                    club_id=TARGET_CLUB,
                    tupian_url=z.tupian_url or '',
                    shenhezhuangtai=SHENHE,
                    paixu=int(z.paixu or 0),
                    shangjia_zhuangtai=bool(getattr(z, 'shangjia_zhuangtai', True)),
                    fengjin_zhuangtai=bool(getattr(z, 'fengjin_zhuangtai', True)),
                    dianpu=None,
                    dianpu_leixing=None,
                )
                zone_id_map[z.id] = row.id
                stats['zones_created'] += 1

            for p in src_products:
                if p.leixing_id not in leixing_ids:
                    raise CommandError(f'商品 {p.id} 类型 {p.leixing_id} 不在审核列表')
                dst_zq = zone_id_map.get(p.zhuanqu_id)
                if not dst_zq:
                    raise CommandError(
                        f'商品「{p.biaoqian}」id={p.id} 无法映射 zhuanqu_id={p.zhuanqu_id}'
                    )
                if not clear_target:
                    exist_p = Shangpin.query.filter(
                        club_id=TARGET_CLUB,
                        leixing_id=p.leixing_id,
                        zhuanqu_id=dst_zq,
                        biaoqian=p.biaoqian,
                        shenhezhuangtai=SHENHE,
                        dianpu__isnull=True,
                    ).first()
                    if exist_p:
                        continue
                Shangpin.query.create(
                    biaoqian=p.biaoqian,
                    jiage=p.jiage,
                    kucun=p.kucun,
                    leixing_id=p.leixing_id,
                    zhuanqu_id=dst_zq,
                    zhenshi_xiaoliang=0,
                    duiwai_xiaoliang=0,
                    jieshao=p.jieshao,
                    xiadan_xuzhi=p.xiadan_xuzhi,
                    guize_tupian=p.guize_tupian or '',
                    tupian_url=p.tupian_url or '',
                    yaoqiuleixing=p.yaoqiuleixing,
                    huiyuan_id=p.huiyuan_id,
                    yongjin=p.yongjin,
                    kaioi_ewai_dashou_fencheng=bool(p.kaioi_ewai_dashou_fencheng),
                    ewai_dashou_fencheng=p.ewai_dashou_fencheng,
                    paixu=int(p.paixu or 0),
                    shenhezhuangtai=SHENHE,
                    shangjia_zhuangtai=bool(p.shangjia_zhuangtai),
                    fengjin_zhuangtai=bool(p.fengjin_zhuangtai),
                    shenhe_zhuangtai=bool(getattr(p, 'shenhe_zhuangtai', True)),
                    club_id=TARGET_CLUB,
                    shi_zhuanpan=False,
                    dianpu=None,
                    dianpu_leixing=None,
                )
                stats['products_created'] += 1

            # 启用审核类型上架配置
            for lx in audit_types:
                src_cfg = ClubShangpinLeixingConfig.query.filter(
                    club_id=SOURCE_CLUB, leixing_id=lx.id,
                ).first()
                dst_cfg = ClubShangpinLeixingConfig.query.filter(
                    club_id=TARGET_CLUB, leixing_id=lx.id,
                ).first()
                icon = ''
                paixu = int(getattr(lx, 'paixu', 0) or 0)
                if src_cfg:
                    icon = src_cfg.tupian_url or ''
                    paixu = int(src_cfg.paixu or paixu)
                if dst_cfg is None:
                    ClubShangpinLeixingConfig.query.create(
                        club_id=TARGET_CLUB,
                        leixing_id=lx.id,
                        is_enabled=True,
                        tupian_url=icon,
                        paixu=paixu,
                    )
                    stats['cfg_created'] += 1
                else:
                    changed = False
                    if not dst_cfg.is_enabled:
                        dst_cfg.is_enabled = True
                        changed = True
                    if icon and not (dst_cfg.tupian_url or '').strip():
                        dst_cfg.tupian_url = icon
                        changed = True
                    if changed:
                        dst_cfg.save()
                        stats['cfg_enabled'] += 1

        self.stdout.write(self.style.SUCCESS(
            f'\n完成: {stats}\n'
            f'龙先生(lxs)未改动；小溪(xx)已具备审核目录。\n'
            f'请用小溪小程序(CLUB_ID=xx)重新编译验证。'
        ))
