a
    i_*                     @  s  d dl mZ d dlZd dlZd dlmZ d dlmZ d dlmZm	Z	m
Z
mZmZ d dlmZmZmZmZmZmZ d dlmZmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dlm Z m!Z! d dl"m#Z$ d dl%m&Z&m'Z( d dl)m*Z* eddgdZ+eeeef Z,eddZ-d a.dg ddg dddg dddg dddg dddg d dd!g d"dd#g d$dd%g d&dd'	Z/G d(d) d)eZ0G d*d+ d+eZ1e+2d,d)d-d.d/Z3e+2d0d+d-d1d2Z4e+5d3d4d5 Z6e+5d6ed7d8d9d:ed;d<d=ed;d>d=ed;d?d=fd@dAdAdAdBdCdDZ7G dEdF dFeZ8G dGdH dHeZ9dZdIdJdKdLZ:e+j2dMee:gdNdAdOdPdQdRZ;e+2dSdHd-dTdUZ<e+j2dVee:gdNdAdHdOdWdXdYZ=dS )[    )annotationsN)deque)datetime)	AnnotatedAnyDictListOptional)	APIRouterDependsHeaderHTTPExceptionQuerystatus)	BaseModelField)select)AsyncSession)settings)get_session)Poll
PollStatus)ws)hihaho_clientvoting)parse_branchesz/hihahohihaho)prefixtags   )maxlenz3The hihaho interactive layer / API has been loaded.)descriptionfieldsz!The viewer has started the video.)actorpercentageToSucceed
session_idvideo_id
video_uuidz,The viewer has reached the end of the video.)
r#   historyZscoreZmaxScoreZscaledResultr$   Zpassedr%   r&   r'   z#The viewer has answered a question.)r#   ZcorrecttypeZ
answerTextZ	startTimeZendTimeZpointsr(   r%   r&   r'   z.The viewer has submitted an optional variable.)namevaluer%   r&   r'   z)The viewer has clicked on an interaction.)Zinteraction_namer+   actionr%   r'   z&The viewer has clicked on a menu item.)titler,   r%   r&   r'   z)The viewer has clicked on a chapter item.)r-   
start_timer%   r'   zDPlayback heartbeat called roughly every 100ms while the video plays.)ZcurrentTimevolumeduration)	initZhihaho_startedZhihaho_endedZhihaho_answerZ"hihaho_optional_variable_submittedZhihaho_interaction_clickedZhihaho_menu_item_clickedZhihaho_chapter_item_clickedonTimec                   @  s.   e Zd ZU dZded< ded< dZded< dS )BranchNotifyBody strfilm_session_id
branch_keyNOptional[Dict[str, Any]]metadata)__name__
__module____qualname__r6   __annotations__r9    r>   r>   HC:\Users\jasmi\Projects\line-hihaho-voting\backend\app\routers\hihaho.pyr3   Y   s   
r3   c                   @  s   e Zd ZU dZded< dZded< dZded< dZded< dZded< dZ	ded< d	Z
d
ed< dZded< dZded< dZded< dS )DebugEventBodyr4   r5   room_idpoll_idfilm_urlevent_idorigin
event_typeFboolsource_is_iframereceived_at_clientNr   rawr8   r9   )r:   r;   r<   rA   r=   rB   rC   rD   rE   rF   rH   rI   rJ   r9   r>   r>   r>   r?   r@   _   s   
r@   z/branchbodyc                   s    t j| jpd| j| jdI dH S )zJProxy to hihaho when API is configured; otherwise returns skipped payload.zdefault-session)r6   r7   r9   N)r   Znotify_branch_resultr6   r7   r9   rK   r>   r>   r?   notify_branchl   s
    rM   z/events/debugc                   sJ   t d7 a |  }t |d< t  d |d< t| ddtt| jdS )N   Z
server_seqZZreceived_at_serverT)okZstoredcountZlatest_event_id)	
_DEBUG_SEQ
model_dumpr   utcnow	isoformat_DEBUG_EVENTSappendlenrD   )rL   payloadr>   r>   r?   ingest_debug_eventv   s    
rZ   z/events/specc                     s
   dt dS )NT)rP   items)HIHAHO_EVENT_SPECSr>   r>   r>   r?   hihaho_event_specs   s    r]   z/events/debug/latest   rN   d   )geler4   zfilter by room id)r!   zfilter by poll idzsubstring matchintr5   )limitrA   rB   rF   c                   sp   t t}rfdd|D }r4fdd|D }|rR|   fdd|D }||  d  }dt||dS )Nc                   s$   g | ]}t |d d kr|qS )rA   r4   r5   get.0r)rA   r>   r?   
<listcomp>       z'latest_debug_events.<locals>.<listcomp>c                   s$   g | ]}t |d d kr|qS )rB   r4   rd   rf   )rB   r>   r?   ri      rj   c                   s(   g | ] } t |d d v r|qS )rF   r4   )r5   re   lowerrf   )needler>   r?   ri      rj   T)rP   rQ   r[   )listrV   rk   rX   )rc   rA   rB   rF   rowsr>   )rl   rB   rA   r?   latest_debug_events   s    ro   c                   @  s,   e Zd ZU dZded< eddZded< dS )	BranchOptionNamesr4   r5   r-      )
min_length	List[str]option_namesN)r:   r;   r<   r-   r=   r   rt   r>   r>   r>   r?   rp      s   
rp   c                   @  s@   e Zd ZU ded< eedZded< edd dd	Zd
ed< dS )InteractionSetupBodyzDict[str, Any]interactions)default_factoryzList[BranchOptionNames]branchesc                   C  s   ddgS )Nu   選項Au   選項Br>   r>   r>   r>   r?   <lambda>   rj   zInteractionSetupBody.<lambda>zKFallback option names when branches list is shorter than detected branches.)rw   r!   rs   default_option_namesN)r:   r;   r<   r=   r   rm   rx   rz   r>   r>   r>   r?   ru      s   
ru   z4Annotated[Optional[str], Header(alias='X-Host-Key')]Z
x_host_keyc                   s&   t js
d S | t jkr"ttjddd S )Nzinvalid host key)status_codedetail)r   host_api_keyr   r   HTTP_403_FORBIDDENr{   r>   r>   r?   _require_host_key   s    
r   z/rooms/{room_id}/reset)dependencies
SessionDep)rA   sessionc                   s   ddl m} ddlm} |tttj| kI dH 	 }|rdd |D }||||j
|I dH  |D ]}||I dH  qt| I dH  t| I dH  dt|dS )	zADelete all polls/votes for a room and broadcast a clean snapshot.r   deleteVoteNc                 S  s   g | ]
}|j qS r>   idrg   pr>   r>   r?   ri      rj   zreset_room.<locals>.<listcomp>T)rP   Zdeleted_polls)
sqlalchemyr   app.models.entitiesr   execr   r   whererA   allrB   in_commit	ws_routerbroadcast_room_snapshotrX   )rA   r   	sa_deleter   existingpoll_idsr   r>   r>   r?   
reset_room   s    "r   z/interactions/parsec                   s:   | j dg }t|ts"tddt|}dt||dS )zHParse interaction JSON and return detected branch schedules (read-only).rv     *interactions.interactions must be an arrayT)rP   branch_countrx   )rv   re   
isinstancerm   r   r   rX   )rL   raw_interactionsrx   r>   r>   r?   parse_interaction_json   s
    

r   z(/rooms/{room_id}/setup-from-interactions)rA   rL   r   c                   s  ddl m} ddlm} ddlm}m} |jdg }t	|t
sJtddt|}|s`tdd||| | I d	H  |tttj| kI d	H  }	|	rd
d |	D }
||||j|
I d	H  |	D ]}||I d	H  q| I d	H  g }t|D ]Z\}}|t|jk r"|j| nd	}|rJt|jt|d krJ|jn|j}|rd|jrd|jnd|d  }i }t|d D ]>\}}|t|kr q|| }dd|d dd||< qttt | |tj |d	t|d  ddt!j"d}||dgd|d  gdddid|t#|d |d |d |d |d d	 |$| |%| q|& I d	H  |D ]}|'|I d	H  qnt()| I d	H  dd l*m+  d!| t|| fd"d|D d#S )$zParse interaction JSON, create a room and one draft poll per branch.

    Each poll is pre-configured with the correct trigger time, voting duration,
    pause action, and winner jump actions derived from the JSON hotspots.
    r   r   r   )ensure_roomset_poll_configrv   r   r   z6No branch decision points detected in interaction JSONNc                 S  s   g | ]
}|j qS r>   r   r   r>   r>   r?   ri      rj   z+setup_from_interactions.<locals>.<listcomp>optionsu   劇情選擇 rN   ZpostmessageZjumpposition)commandr   )r)   rY   F)ensure_ascii)r   rA   r-   Zoptions_jsonr   r2   zcurrentTime>=r.   r   pauseduration_secondsend_timeZdefault_jump_time)	Ztrigger_namesZtrigger_keysZpause_actionwinner_actionsr   Zbranch_start_timeZbranch_end_timeZbranch_default_jumpZbranch_optionspoll_outTc                   s   g | ]} |qS r>   r>   r   r   r>   r?   ri   H  rj   )rP   rA   r   rx   polls),r   r   r   r   Zapp.services.votingr   r   rv   re   r   rm   r   r   r   r   r   r   rA   r   rB   r   flush	enumeraterX   rx   rt   rz   r-   r5   uuiduuid4jsondumpsr   draftrb   addrW   r   refreshr   r   Zapp.routers.pollsr   )rA   rL   r   r   r   r   r   r   rx   r   r   r   Zcreated_pollsidxbranchZ
branch_cfgrt   r-   r   jZopt_infor*   pollr>   r   r?   setup_from_interactions   s    


"


	

r   )N)>
__future__r   r   r   collectionsr   r   typingr   r   r   r   r	   fastapir
   r   r   r   r   r   pydanticr   r   sqlmodelr   sqlmodel.ext.asyncio.sessionr   
app.configr   app.dbr   r   r   r   app.routersr   r   Zapp.servicesr   r   Z
voting_svcZ!app.services.interaction_scheduler   routerr   rV   rR   r\   r3   r@   postrM   rZ   re   r]   ro   rp   ru   r   r   r   r   r>   r>   r>   r?   <module>   s    
?	




 		