o
    -Fj/                     @   sH   d dl mZ d dlmZ d dlmZ d dlmZmZ G dd deZ	dS )    )defaultdict)BaseCommand)transaction)
CraptitudeGameSessionc                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )Commanda$  Remove duplicate craptitudes, keeping ONE row per (category, roundNumber). GameSession references pointing at a discarded duplicate are reassigned to the kept row first, so no game sessions are cascade-deleted. Run this before applying the unique (category, roundNumber) constraint migration.c                 C   s   |j dddd d S )Nz	--dry-run
store_truez2Report what would change without writing anything.)actionhelp)add_argument)selfparser r   H/var/www/html/premium_crap/api/management/commands/dedupe_craptitudes.pyadd_arguments   s
   
zCommand.add_argumentsc                    s  |d }t t}tj dD ]}||j|jf | qdd |	 D }|s5| j
| jd d S d}d}t  t|	 D ]z\\}	}
}| |  fdd|D }d	d |D }|  |}tjj|d
}| }| j
d|	 d|
 d j dt| d	|rd| dnd |rd| nd  |s|r j|d |r|j d tjj|d  |t|7 }||7 }qD|rtd W d    n1 sw   Y  |rdnd}| j
| j| d| dt| d| d |s| j
d d S d S )Ndry_runpkc                 S   s"   i | ]\}}t |d kr||qS )   )len).0keyrowsr   r   r   
<dictcomp>    s   " z"Command.handle.<locals>.<dictcomp>u#   ✅ No duplicate craptitudes found.r   c                    s   g | ]
}|j  j kr|qS r   r   r   rkeeperr   r   
<listcomp>+   s    z"Command.handle.<locals>.<listcomp>c                 S   s   g | ]}|j qS r   r   r   r   r   r   r   ,   s    )craptitude_id__inz  category=z round=z
: keep id=z	, delete z duplicate(s)z, reassign z session(s) z, carried prefixes )update_fields)
craptitude)pk__inTz[dry-run] would deleteu   ✅ Deleted z  duplicate craptitude(s) across z slot(s); reassigned z game session(s).zNext: run `python manage.py makemigrations api` and `python manage.py migrate` to add the unique (category, roundNumber) constraint.)r   listr   objectsallorder_bycategory_idroundNumberappenditemsstdoutwritestyleSUCCESSr   atomicsorted_pick_keeper_backfill_prefixesr   filtercountr   r   saveupdatedeleteset_rollback)r   argsoptionsr   groupsc
dup_groupstotal_deletedtotal_reassignedr)   round_numberr   dupesdupe_idscarriedsessionssession_countprefixr   r   r   handle   sl   



"zCommand.handlec                    s^   g }dD ]( t | pd rqt fdd|D d}|r,t| t |  |  q|S )z
        Fill any empty prefix on the keeper from a duplicate that has it.
        Mutates keeper in memory and returns the list of field names to save (empty if nothing changed).
        )diaperPrefixdumpsterPrefixr    c                 3   s&    | ]}t | p
d  r|V  qdS )r    N)getattrstrip)r   dfieldr   r   	<genexpr>`   s   $ z-Command._backfill_prefixes.<locals>.<genexpr>N)rL   rM   nextsetattrr+   )r   r   rC   rE   donorr   rO   r   r4   W   s   
zCommand._backfill_prefixesc                 C   s   dd }t ||dS )z
        Choose which duplicate to keep. Preference order:
          1. active (deletedAt is None) over soft-deleted,
          2. has prefix text over empty,
          3. lowest primary key.
        c                 S   s8   | j d u }t| jp
d p| jpd }||| j fS )Nr    )	deletedAtboolrJ   rM   rK   r   )r   active
has_prefixr   r   r   scorem   s   
 z#Command._pick_keeper.<locals>.score)r   )max)r   r   rY   r   r   r   r3   f   s   zCommand._pick_keeperN)__name__
__module____qualname__r
   r   rI   r4   r3   r   r   r   r   r   	   s    ?r   N)
collectionsr   django.core.management.baser   	django.dbr   
api.modelsr   r   r   r   r   r   r   <module>   s
    