
    @Wj%                        S r SSKJr  SSKJrJr  SSKJr  SSKJ	r	J
r
JrJrJr  SSKJr  SS	KJrJr  SS
KJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJrJr   " S S5      r g)a'  Top-level orchestrator for the Product Decision Engine.

Workflow:
    Receive product JSON -> extract SKUs -> match freight per SKU
    -> analyze each SKU -> compare SKUs -> product-level analysis
    -> final recommendation -> response dict.

Everything runs in memory; nothing is persisted.
    )annotations)AnyOptional   )	constants)as_listclampfirst_presentsaturating_scoreunwrap_response   )MarketAnalyzer)ProductAnalysisProductAnalyzer)RecommendationEngine)RiskAnalyzer)StoreAnalyzer)StrengthAnalyzer)SkuAnalyzer)SkuDecisionSkuDecisionEnginec                      \ rS rSrSr        SS jrSS jr    SS jrSS jr\	SS j5       r
\	SS j5       r\	SS	 j5       r\	SS
 j5       r      SS jrSrg)DecisionEngine   z@Coordinates every analyzer and assembles the final API response.c                f   [        U=(       d    0 5      U l        U R                  U=(       d    / 5      U l        [	        U5      U l        [        5       U l        [        5       U l	        [        5       U l        [        5       U l        [        5       U l        [!        5       U l        [%        5       U l        g N)r   _product_json_index_freight_freight_by_skufloat_profit_marginr   _product_analyzerr   _store_analyzerr   _sku_enginer   _market_analyzerr   _risk_analyzerr   _strength_analyzerr   _recommendation_engine)selfproduct_jsonfreight_resultsprofit_margins       ږ/Users/waleedhassanin/Documents/snowflake_co_dev_github/snow_flake_back_end_deploy/mama_care_api/ali_express_ds/pms/engine/services/decision_engine.py__init__DecisionEngine.__init__   s     -\-?R@#22?3HbI#M2!0!2,,. . 0*n"2"4&:&<#    c           
     D   U R                   R                  U R                  5      nU R                  R                  U R                  5      nU R	                  U5      nUR
                  S:  a  UR
                  OSnU R                  X45      nU R                  U5      nU R                  R                  XU5      nU R                  R                  XU5      nU R                  R                  XU5      n	U R                  R                  XXWX5      n
U R                  XXVXxU	U
5      $ )z:Execute the full workflow and return the response payload.r   N)r"   analyzer   r#   _popularity_scorescore_analyze_skus
_rank_skusr%   r&   r'   r(   	recommend_build_response)r)   productstorepopularity_scorestore_signalsku_decisionsrankingsmarketriskstrengthrecommendations              r-   runDecisionEngine.run4   s   ((001C1CD$$,,T-?-?@11':&+kkAou{{4**+;J??=1&&..w}M""**7=I**227=Q44>>M4
 ##MV8
 	
r0   c                &   U R                  5       nU R                  U5      n/ nU Hg  n[        [        USSS95      nUR	                  U R
                  R                  UU R                  R                  U5      U R                  UUUS95        Mi     U$ )N)sku_idskuIdid default)sku_dtofreight_jsonr,   r;   store_scoremax_supplier_price)
_extract_sku_dtos_max_supplier_pricestrr
   appendr$   r2   r   getr!   )r)   r;   rN   sku_dtosrO   	decisionsrL   rF   s           r-   r5   DecisionEngine._analyze_skusK   s    ))+!55h?')	Gw0ISUVWF  ((#!%!5!5!9!9&!A"&"5"5%5 +'9 ) 	   r0   c                    [        U R                  S5      n[        U5       Vs/ s H  n[        U[        5      (       d  M  UPM     sn$ s  snf )N)z,ae_item_sku_info_dtos.ae_item_sku_info_d_t_oae_item_sku_info_dtossku_info_dtosskus)r
   r   r   
isinstancedict)r)   	containerdtos      r-   rP    DecisionEngine._extract_sku_dtos_   sD    !?
	
  'y1K1ZT5J1KKKs   A
A
c                    [        5       nU  Vs/ s H  o!R                  U5      R                  PM     nn[        USS9$ s  snf )z9Anchor used to compare SKU prices against their siblings.        rJ   )r   r2   supplier_pricemax)rU   analyzerr_   pricess       r-   rQ   "DecisionEngine._max_supplier_priceg   sA     =BJK(3""3'66(K63'' Ls   $?c           	         0 nU  H^  n[        U[        5      (       d  M  [        [        USSS95      n[        US5      nU(       d  MC  [        U[        5      (       d  MZ  XAU'   M`     U$ )N)rG   rF   rI   rJ   )freightJsonrM   freight)r\   r]   rR   r
   )r+   indexentryrF   rj   s        r-   r   DecisionEngine._index_freightn   sa    !#$EeT**u.A2NOF#E+UVGv*Wd33 'f % r0   c                   ^  T (       d  S Vs0 s H  oS_M     sn$ SSU 4S jjjnU" S 5      U" S SS9U" S 5      U" S	 5      U" S
 5      U" S SS9U" S 5      U" S SS9S.$ s  snf )zDFind the winner per business dimension. ``None`` when no SKU exists.)bestOverallSkulowestCostSkuhighestProfitSkuhighestMarginSkuhighestStockSkufastestDeliverySkubestValueSkulowestShippingCostSkuNc                J   > [        TXS9S   nUR                  R                  $ )N)keyreverser   )sortedskurF   )key_fnry   bestrV   s      r-   winner)DecisionEngine._rank_skus.<locals>.winner   s"    )A!DD88??"r0   c                .    U R                   R                  $ r   resultr4   ds    r-   <lambda>+DecisionEngine._rank_skus.<locals>.<lambda>   s    qxx~~r0   c                .    U R                   R                  $ r   )pricing
total_costr   s    r-   r   r      s    aii.B.Br0   F)ry   c                .    U R                   R                  $ r   )r   estimated_profitr   s    r-   r   r      s    1K1Kr0   c                .    U R                   R                  $ r   )r   marginr   s    r-   r   r      s    1A1Ar0   c                .    U R                   R                  $ r   )r{   stockr   s    r-   r   r      s    r0   c                `    U R                   R                  b  U R                   R                  $ S$ )Ng     8@)rj   delivery_days_avgr   s    r-   r   r      s0    99..: ))55 F@EFr0   c                    U R                   R                  S:  a-  U R                  R                  U R                   R                  -  $ S$ )Nr   rb   )r   r   r   r4   r   s    r-   r   r      s=    99''!+ ((..199+?+?? 5145r0   c                .    U R                   R                  $ r   )rj   shipping_costr   s    r-   r   r      s    !))11r0   )T)ry   boolreturnrR    )rV   rx   r~   s   `  r-   r6   DecisionEngine._rank_skus}   s     *  *#I *  	# 	#
 %%=>#$BER &'K L &'A B%&;<"(F# #5 &,15&!
 	
s   A&c                    U R                   S::  a  U R                  S::  a  g[        [        U R                   [        R
                  5      S-  [        U R                  [        R                  5      S-  -   5      $ )a  Product-level popularity shared by every SKU: sales + reviews.

Uses a saturating (square-root) curve so moderate history earns a
moderate score. Returns ``None`` when neither metric is available,
letting downstream weights renormalize instead of scoring zero.
r   Ng333333?g?)sales_countreview_countr	   r   CSALES_FOR_FULL_POPULARITYREVIEWS_FOR_FULL_POPULARITY)r9   s    r-   r3    DecisionEngine._popularity_score   ss     !#(<(<(AW00!2M2MNQTTw33 <<>@CDD
 	
r0   c	                X   U(       a  [        US S9OS n	0 SUR                  _S[        UR                  5      _S[        UR                  5      _SU	(       a  U	R
                  R                  SS.OS _S	U_S
UR                  5       _SU	(       a  U	R                  R                  5       OS _SUR                  5       _SUR                  5       _S[        UR                  S5      UR                  =(       a:    UR                  R                  5        V
Vs0 s H  u  pU
[        US5      _M     snn
S._SU Vs/ s H  oR                  5       PM     sn_SUR                  _SUR                  _SUR                  _SUR                  _SUR                  _SUR                   _$ s  snn
f s  snf )Nc                .    U R                   R                  $ r   r   r   s    r-   r   0DecisionEngine._build_response.<locals>.<lambda>   s    QXX^^r0   )rx   decision
confidenceoverallScorebestSkuzHighest overall score)rG   reasonr>   r?   r   r:   r9   scoresr   )overall	breakdownskuAnalysis	strengthsriskssummaryconfidenceReasonsmarketRecommendationskuRecommendation)rd   r   roundr   overall_scorer{   rF   to_dictr   score_breakdownitemsr   r   r   confidence_reasonsmarket_recommendationsku_recommendation)r)   r9   r:   r=   r>   r?   r@   rA   rB   r}   kvr   s                r-   r8   DecisionEngine._build_response   s     #;<"& 	
//
% 9 9:
 E.">">?
  ((//5LM!
 
 fnn&
 t||++-4
 U]]_
 w(
  !=!=qA+;; I!/!?!?!E!E!GI!G a^!GI
& ?AIIK?'
( ++)
* TZZ+
, ~---
.  !B!B/
0 #N$H$H1
2  !B!B3
 	
 I @s   F!6F')
r   r%   r"   r   r!   r(   r&   r$   r#   r'   N)r*   r]   r+   
list[dict]r,   r    r   None)r   r]   )r;   'float | None'rN   r   r   list[SkuDecision])r   r   )rU   r   r   r    )r+   r   r   zdict[str, dict])rV   r   r   zdict[str, Optional[str]])r9   r   r   r   )r=   r   r>   r]   r   r]   )__name__
__module____qualname____firstlineno____doc__r.   rC   r5   rP   staticmethodrQ   r   r6   r3   r8   __static_attributes__r   r0   r-   r   r      s    J== $= 	=
 
=*
.#16G(L ( ( 	 	  
  
J 
 
$)
 )	)

 )
 
)
r0   r   N)!r   
__future__r   typingr   r   r   r   utils.helpersr   r	   r
   r   r   analyzers.market_analyzerr   analyzers.product_analyzerr   r   analyzers.recommendation_enginer   analyzers.risk_analyzerr   analyzers.store_analyzerr   analyzers.strength_analyzerr   analyzers.sku.sku_analyzerr   !analyzers.sku.sku_decision_enginer   r   r   r   r0   r-   <module>r      sG    #   &@ @ 6 H A 1 3 9 3 MC
 C
r0   