
    Ei$                        d Z ddlmZ ddlZddlZddlmZmZmZm	Z	m
Z
 ddlmZ ddlmZ ddlmZmZmZ  G d d	      Zy)
u%  SceneStillWriter — PlannedStill 리스트 → scene_still DB UPSERT.

책임:
  1) 기존 scene_still row 로드 → UPSERT (ID 보존)
  2) 계획에 없는 기존 row는 stale 마킹 (이미지 연결 보존 — DELETE 금지)
  3) shot_dependency 또는 scene_dependency(legacy)에서 dependent_scene_id 갱신
  4) scene_summary / shot_type 컬럼 전파

UPSERT 정책 (baseline 동작):
  - key = (scene_index, shot_index) — shot-based (v4/unselected)
  - 기존 row가 shot_index IS NULL이면 key = (still_index, None) — legacy 호환
    )annotationsN)AnyDictListOptionalTuple)text)Session)CheckpointBundlePlannedStillStillKeyc                  l    e Zd Zd	dZd
dZddZ	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 ddZddZ	 	 	 	 	 	 ddZ	y)SceneStillWriterc                x    || _         || _        || _        || _        t	        j
                  t              | _        y N)db
project_id
episode_idnowlogging	getLogger__name__logger)selfr   r   r   r   s        e/Users/manta/Documents/Projects/TheRoad-I1/backend/app/services/checkpoint_sync/scene_still_writer.py__init__zSceneStillWriter.__init__   s0    $$''1    c                   ddl m} | j                  |      }|j                  rH|j                  s<| j
                  j                  t        d      | j                  | j                  d       t               }i }|D ]A  }|j                  |j                         |j                  |v rz||j                     }|j                  |_        |j                  |_        |j                  j!                         D ]  \  }	}
t#        ||	|
        |j$                  ||j                  <   t'        t)        j*                               }| j
                  j                   |d
|| j                  | j                  |j                  |j                  |j,                  | j.                  d|j                         |||j                  <   D |j                  s,|j!                         D ]  \  }}||vsd|_        d|_         n|r| j2                  j5                  d       | j
                  j7                          |j8                  r| j;                  |j8                  |       n'| j=                  |j>                  |j@                  |       |r%| j2                  j5                  d	tC        |             | jE                  |jF                         | jI                  |jJ                  |jL                         tC        |      S )Nr   )
SceneStillz^UPDATE scene_still SET dependent_scene_id = NULL WHERE project_id = :pid AND episode_id = :eid)pideid)idr   r   still_indexscene_indext2i_composer_version
created_atstaleua   scene_still sync: partial scene_detail — stale marking deferred (awaiting completed checkpoint)z)Synced %d scene_stills (shot-based) to DB )'app.models.projectr   _load_existingshot_dep_completed
sd_partialr   executesql_textr   r   setaddkeyr#   r$   columnsitemssetattrr"   struuiduuid4r%   r   statusr   infoflush	shot_deps_apply_shot_deps_apply_legacy_depsscenesdep_maplen_sync_scene_summaryscene_summaries_sync_shot_typeshot_cine_shotsscene_cine_scenes)r   plannedbundler   existing_by_keynew_keysshot_key_to_idpsscolvalnew_idr2   s                r   writezSceneStillWriter.write%   sZ   1--j9
 $$V->->GGOOH@ t?A
 .0ALLuu'$QUU+!"!" !"		 1HCBS) !2(*quu%TZZ\*J 	## ! !)*)?)?#xx	 ii	 	 )/quu%1 :   *002Rh&%'BN 'BI 3 KK2 	 !!&"2"2NC##FMM6>>>RKK;S\
 	  !7!78V33V5M5MN7|r   c                p   | j                   j                  |      j                  |j                  | j                  k(  |j                  | j                  k(        j                         }i }|D ]G  }|j                  (|j                  |||j                  |j                  f<   7|||j                  d f<   I |S r   )	r   queryfilterr   r   allr$   
shot_indexr#   )r   r   rowsoutrM   s        r   r+   zSceneStillWriter._load_existingr   s    ww}}Z(//!!T__4!!T__4
 #% 	 $&B~~)bmm.G79R^^R]]34.0R^^T*+	 
 
r   c                f   |D ]  }|j                  dg       }|s|d   }|j                  |j                  d      |j                  d      f      }|j                  |j                  d      |j                  d      f      }|s|s| j                  j                  t        d      ||d        y )Nlocation_refsr   r$   rV   @UPDATE scene_still SET dependent_scene_id = :dep WHERE id = :siddepsid)getr   r.   r/   )r   r<   rK   r]   loc_refsref	dep_stillstill_ids           r   r=   z!SceneStillWriter._apply_shot_deps   s    
 Cww3H1+C&**')>?I &))')>?H XV!$X68 r   c                   |D ]  }|j                  dd      }|j                  t        |      |j                  |i             }|sC|j                  dg       }|r|d   n|j                  d      }t        |t              r|j                  d      n|}	|	|j                  |	d f      nd }
|j                  |d f      }|
s|s| j                  j                  t        d      |
|d        y )Nr$   r   rZ   prev_refr[   r\   )r_   r6   
isinstancedictr   r.   r/   )r   r?   r@   rK   ssidep_infor`   prev_rawre   dep_idrc   s               r   r>   z#SceneStillWriter._apply_legacy_deps   s     A}a(B{{3r7GKKB,?@H||OR8H&.x{HLL4LH6@46Px||M2V^H=E=Q^''4(89W[F%))2t*5H(V!!(35 r   c           	     D   |sy |D ]c  }|j                  d      }|j                  dd      }| j                  j                  t        d      | j                  | j
                  ||d       e | j                  j                          | j                  j                  d       y )Nr$   scene_summary zsUPDATE scene_still SET scene_summary = :summary WHERE project_id = :pid AND episode_id = :eid AND scene_index = :si)r    r!   ri   summaryz$Synced scene_summary from checkpoint)	r_   r   r.   r/   r   r   r;   r   r:   )r   	summariesitemri   r	   s        r   rB   z$SceneStillWriter._sync_scene_summary   s    D-(B88OR0DGGOOHV tbUYZ\  	?@r   c                   |r|D ]  }|j                  d      }|j                  d      }|j                  di       j                  dd      }|j                  di       j                  dd      }| j                  j                  t        d      | j                  | j
                  ||||d        | j                  j                          | j                  j                  d	       y |r|D ]  }|j                  d      }|j                  d
g       }	|	r|	d   j                  dd      n|j                  dd      }
t        |	      dkD  r|	d   j                  dd      n|j                  dd      }| j                  j                  t        d      | j                  | j
                  ||
|d        | j                  j                          | j                  j                  d       y y )Nr$   rV   technique_1namero   technique_2zUPDATE scene_still SET shot_type_1 = :s1, shot_type_2 = :s2 WHERE project_id = :pid AND episode_id = :eid AND scene_index = :si AND shot_index = :shot_idx)r    r!   ri   shot_idxs1s2z4Synced shot_type from shot_cinematography checkpointshotsr   shot_1   shot_2zUPDATE scene_still SET shot_type_1 = :s1, shot_type_2 = :s2 WHERE project_id = :pid AND episode_id = :eid AND scene_index = :si)r    r!   ri   rx   ry   z>Synced shot_type from scene_cinematography checkpoint (legacy))
r_   r   r.   r/   r   r   r;   r   r:   rA   )r   rE   rF   scri   rw   t1t2csrz   rx   ry   s               r   rD   z SceneStillWriter._sync_shot_type   s   
 %VVM*66,/VVM2.2262>VVM2.2262>G!  ??4??("BH	I & GGMMOKKST'VVM*w+16U1X\\&"-BFF8R<P14UaU1X\\&"-RVVHVXEYZ!  ??4??"TV^`ac ( GGMMOKK]^ r   N)r   
OrmSessionr   r6   r   r6   r   r6   )rG   zList[PlannedStill]rH   r   returnint)r   zDict[StillKey, Any])r<   List[Dict[str, Any]]rK   Dict[StillKey, str]r   None)r?   r   r@   zDict[str, Dict[str, Any]]rK   r   r   r   )rq   r   r   r   )rE   r   rF   r   r   r   )
r   
__module____qualname__r   rQ   r+   r=   r>   rB   rD   r)   r   r   r   r      s    2KZ8'8 ,8 
	8*5$5 +5 ,	5
 
5*A_-_ 0_ 
	_r   r   )__doc__
__future__r   r   r7   typingr   r   r   r   r   
sqlalchemyr	   r/   sqlalchemy.ormr
   r   3app.services.checkpoint_sync._scene_still_contractsr   r   r   r   r)   r   r   <module>r      s9    #   3 3 ' 0 x_ x_r   