# -*- coding: utf-8 -*-
"""
删除 UFO 俱乐部「正常/公共」商品目录（专区 + 商品）及对应 OSS 图片。

范围（必须全部满足，缺一不删）：
  - club_id 固定为 ufo（不可改目标）
  - dianpu IS NULL（公共目录；店铺商品一律不碰）
  - 表：shangpin、shangpin_zhuanqu
  - OSS：商品 tupian_url / guize_tupian、专区 tupian_url

不碰：
  - 其它俱乐部（xq / lxs / xzj 等）
  - 店铺商品（dianpu 非空）
  - 全局 ShangpinLeixing
  - ClubShangpinLeixingConfig、订单、轮播、转盘、统计等

用法:

  python manage.py delete_ufo_public_catalog
  python manage.py delete_ufo_public_catalog --apply --i-confirm-club=ufo
"""
from __future__ import annotations

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

ALLOWED_CLUB_ID = 'ufo'
NAME_HINT = 'UFO'  # Club.name 须含此字样（大小写不敏感）


class Command(BaseCommand):
    help = '删除 UFO 公共商品+专区及 OSS 图（默认 dry-run；仅 ufo）'

    def add_arguments(self, parser):
        parser.add_argument(
            '--apply',
            action='store_true',
            help='真正删库 + 删 OSS（默认仅打印清单）',
        )
        parser.add_argument(
            '--i-confirm-club',
            type=str,
            default='',
            help='必须等于 ufo，才允许 --apply',
        )
        parser.add_argument(
            '--club-id',
            type=str,
            default=ALLOWED_CLUB_ID,
            help='仅允许 ufo；传其它值会直接拒绝',
        )

    def handle(self, *args, **options):
        from jituan.models import Club
        from products.models import Shangpin, ShangpinZhuanqu
        from utils.oss_utils import delete_from_oss

        club_id = (options.get('club_id') or '').strip()
        apply = bool(options.get('apply'))
        confirm = (options.get('i_confirm_club') or '').strip()

        if club_id != ALLOWED_CLUB_ID:
            raise CommandError(
                f'安全拦截：本命令只允许 club_id={ALLOWED_CLUB_ID!r}，你传的是 {club_id!r}'
            )

        club = Club.query.filter(club_id=ALLOWED_CLUB_ID).first()
        if not club:
            raise CommandError(f'俱乐部 {ALLOWED_CLUB_ID} 不存在，无需删除')
        if NAME_HINT.lower() not in (club.name or '').lower():
            raise CommandError(
                f'安全拦截：club_id={ALLOWED_CLUB_ID!r} 的 name={club.name!r} '
                f'不含「{NAME_HINT}」，拒绝执行。'
            )

        if apply and confirm != ALLOWED_CLUB_ID:
            raise CommandError(
                '安全拦截：--apply 必须同时传 --i-confirm-club=ufo\n'
                '  例：python manage.py delete_ufo_public_catalog --apply --i-confirm-club=ufo'
            )

        zones = list(
            ShangpinZhuanqu.query.filter(
                club_id=ALLOWED_CLUB_ID,
                dianpu__isnull=True,
            ).order_by('id')
        )
        products = list(
            Shangpin.query.filter(
                club_id=ALLOWED_CLUB_ID,
                dianpu__isnull=True,
            ).order_by('id')
        )

        oss_urls = []
        for z in zones:
            if z.tupian_url:
                oss_urls.append(('zone', z.id, z.tupian_url))
        for p in products:
            if p.tupian_url:
                oss_urls.append(('product', p.id, p.tupian_url))
            if p.guize_tupian:
                oss_urls.append(('product_guize', p.id, p.guize_tupian))

        mode = 'APPLY' if apply else 'DRY-RUN'
        self.stdout.write(self.style.NOTICE(
            f'\n===== {mode} 删除 UFO 公共商品目录 =====\n'
            f'club_id={ALLOWED_CLUB_ID} name={club.name!r}\n'
            f'公共专区={len(zones)}  公共商品={len(products)}  '
            f'待删 OSS 路径={len(oss_urls)}\n'
        ))

        self.stdout.write('—— 专区 ——')
        for z in zones[:50]:
            self.stdout.write(
                f'  id={z.id}  mingzi={z.mingzi!r}  leixing_id={z.leixing_id}  '
                f'tupian={z.tupian_url or "-"}'
            )
        if len(zones) > 50:
            self.stdout.write(f'  ... 其余 {len(zones) - 50} 个专区省略')

        self.stdout.write('—— 商品 ——')
        for p in products[:80]:
            self.stdout.write(
                f'  id={p.id}  {p.biaoqian!r}  ¥{p.jiage}  '
                f'zhuanqu_id={p.zhuanqu_id}  tupian={p.tupian_url or "-"}'
            )
        if len(products) > 80:
            self.stdout.write(f'  ... 其余 {len(products) - 80} 个商品省略')

        self.stdout.write(f'—— OSS 将删 {len(oss_urls)} 个对象（相对路径）——')
        for kind, oid, url in oss_urls[:30]:
            self.stdout.write(f'  [{kind}#{oid}] {url}')
        if len(oss_urls) > 30:
            self.stdout.write(f'  ... 其余 {len(oss_urls) - 30} 个省略')

        if not apply:
            self.stdout.write(self.style.WARNING(
                '\n以上仅计划，未删库、未删 OSS。\n'
                '确认无误后：\n'
                '  python manage.py delete_ufo_public_catalog --apply --i-confirm-club=ufo\n'
            ))
            return

        if not zones and not products:
            self.stdout.write(self.style.SUCCESS('无公共专区/商品，无需删除。'))
            return

        with transaction.atomic():
            # 再按条件删一遍，避免误伤其它 club / 店铺商品
            n_prod, _ = Shangpin.query.filter(
                club_id=ALLOWED_CLUB_ID,
                dianpu__isnull=True,
            ).delete()
            n_zone, _ = ShangpinZhuanqu.query.filter(
                club_id=ALLOWED_CLUB_ID,
                dianpu__isnull=True,
            ).delete()

        oss_ok = 0
        oss_fail = 0
        seen = set()
        for _, _, url in oss_urls:
            key = (url or '').strip()
            if not key or key in seen:
                continue
            seen.add(key)
            if delete_from_oss(key):
                oss_ok += 1
            else:
                oss_fail += 1
                self.stderr.write(f'OSS 删除失败（已记日志，继续）: {key}')

        self.stdout.write(self.style.SUCCESS(
            f'\n删除完成: products={n_prod} zones={n_zone} '
            f'oss_ok={oss_ok} oss_fail={oss_fail}\n'
            f'未动：其它俱乐部、店铺商品、全局类型、订单/转盘等。'
        ))
