
    kj                        d Z ddlmZ ddlZddlZddlZdZdZdZdZ	dZ
d	Zdd
ZddZddZddZddZddZdde
d	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy)u  reddit_capi.py — send a Reddit CAPI SignUp conversion event.

Faithful port of the BE team's spec (reddit-capi-signup-python.md), which is itself
a port of app/Services/RedditCapiService.php. Only deviations from that doc:
  - uses httpx (already a dependency) instead of requests
  - `from __future__ import annotations` so `str | None` hints are safe on Python 3.9
Everything about the wire payload is identical.
    )annotationsNzEhttps://ads-api.reddit.com/api/v3/pixels/{pixel_id}/conversion_eventsSignUpAPPWEBSITE
   $0123456789abcdefghijklmnopqrstuvwxyzc                 T    t        t        t        j                         dz              S )zLCurrent unix time in milliseconds (matches PHP round(microtime(true)*1000)).i  )introundtime     :/var/www/python/quitsure-chatbot-onboarding/reddit_capi.py_now_msr      s    uTYY[4'())r   c                b    | dk(  ryd}| dkD  r!t        | d      \  } }t        |   |z   }| dkD  r!|S )zNLowercase base-36 of a non-negative int (matches PHP base_convert(n, 10, 36)).r   0 $   )divmod_BASE36_DIGITS)numberoutrems      r   
_to_base36r   "   sG    {
C
1*VR(S!C' 1* Jr   c                8    |  d| dt        t                      S )z
    Time-based, unique event id.

    Format: "{external_id}-{event_type}-{base36 ms timestamp}"
    For SignUp, event_type is "1". Example: "u12345-1-ms5zraf6".
    -)r   r   )external_id
event_types     r   generate_event_idr   -   s#     ]!J<qGI)>(?@@r   c                    | r| nd}| d| dt        t                      }t        j                  |j	                  d            j                         S )z
    Deduplication id: SHA-256 of "{seed}-{tracking_type}-{base36 ms}".
    seed falls back to 'anon' when external_id is empty.
    anonr   utf-8)r   r   hashlibsha256encode	hexdigest)r   tracking_typeseedraws       r   generate_conversion_idr*   7   sL    
 &;6DF!M?!Jwy$9#:
;C>>#**W-.88::r   c                    t        j                  | j                         j                         j	                  d            j                         S )zGReddit requires SHA-256 of the normalized (trimmed + lowercased) email.r"   )r#   r$   striplowerr%   r&   )emails    r   
hash_emailr/   A   s4    >>%++---/66w?@JJLLr   c                   i }| j                  d      rt        | d         |d<   | j                  d      rt        | d         |d<   | j                  d      rt        | d         |d<   | j                  d      rt        | d         |d<   | j                  d      }t        | j                  d      xs d      j                         }|r(|d	k(  rt        |      |d
<   |S |dk(  rt        |      |d<   |S )z<Assemble the `user` object, including only non-empty fields.r.   r   	client_ip
ip_address
user_agentadvertising_iddevice_typer   iosidfaandroidaaid)getstrr-   )datauserad_iddevices       r   _build_userr@   F   s    DxxDM*Wxx!$}"56]xx k!23\xx l!34\HH%&E-(.B/557FU?u:DL K y u:DLKr   T)test_idenabledtimeoutc               n   |r|r|sdddS t        |       } t        | j                  d      xs dd      | d<   t        | j                  d      xs d      j	                         }| j                  d	      xs |d
v rt
        nt        }| j                  d      xs, t        t        | j                  d      xs d      t              }t               |dt        it        |       d|id}	| j                  d      r| d   |	d<   dd|	gii}
| j                  d      xs |}|r||
d   d<   t        j                  |      }	 t        j                  ||
dd| i|d      }|j                  rddiS d|j                   |j"                  ddS # t        j$                  $ r}dt        |      dcY d}~S d}~ww xY w)a$  
    Send one SignUp conversion event to Reddit.

    Returns:
        {"success": True}                              on 2xx
        {"success": False, "skipped": True}            when disabled/unconfigured
        {"success": False, "error": {...}|"..."}       on HTTP error / exception
    FT)successskippedr   r!   1r5   r   action_source)r6   r8   conversion_idr'   )event_atrH   typer=   metadataclick_idr<   eventsrA   )pixel_idAuthorizationzBearer )jsonheadersrC   follow_redirectsrE   )statusbody)rE   errorN)dictr   r:   r;   r-   ACTION_SOURCE_APPACTION_SOURCE_WEBSITEr*   TRACKING_TYPE_SIGNUPr   r@   ENDPOINTformathttpxpost
is_successstatus_codetext	HTTPError)r<   rO   access_tokenrA   rB   rC   r?   rH   rI   eventrU   effective_test_idurlrespexcs                  r   send_signup_eventri   _   s   " (, T22 :D ,DHH],C,MvsSD-(.B/557FHH_- #'99?T  HH_- 1GDHH]#)r*,@2M
 I& "67D!$m4E xx
 ,jXw'(D+6w"3VY
//8/
,C5zz$~&>?!
 ??t$$ d6F6FPTPYPY+Z[[?? 5 3s8445s$   >.F	 -F	 	F4F/)F4/F4)returnr
   )r   r
   rj   r;   )r   r;   r   r;   rj   r;   )r   r;   r'   r;   rj   r;   )r.   r;   rj   r;   )r<   rW   rj   rW   )r<   rW   rO   r;   rc   r;   rA   z
str | NonerB   boolrC   r
   rj   rW   )__doc__
__future__r   r#   r   r]   r[   rZ   rX   rY   HTTP_TIMEOUT_SECONDSr   r   r   r   r*   r/   r@   ri   r   r   r   <module>ro      s    #   R  !  7*
A;M
< '@5
@5 @5 	@5
 @5 @5 @5 
@5r   