o
    mDWj£%  ã                   @  sÂ   d 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
mZmZmZ ddl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 ddlmZmZ G dd„ dƒZ dS )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                   @  sz   e Zd ZdZd)d
d„Zd*dd„Zd+dd„Zd,dd„Zed-dd„ƒZ	ed.dd„ƒZ
ed/dd„ƒZed0d"d#„ƒZd1d&d'„Zd(S )2ÚDecisionEnginez@Coordinates every analyzer and assembles the final API response.Úproduct_jsonÚdictÚfreight_resultsú
list[dict]Úprofit_marginÚfloatÚreturnÚNonec                 C  sd   t |pi ƒ| _|  |pg ¡| _t|ƒ| _tƒ | _tƒ | _	t
ƒ | _tƒ | _tƒ | _tƒ | _tƒ | _d S ©N)r   Ú_product_jsonÚ_index_freightÚ_freight_by_skur   Ú_profit_marginr   Ú_product_analyzerr   Ú_store_analyzerr   Ú_sku_enginer   Ú_market_analyzerr   Ú_risk_analyzerr   Ú_strength_analyzerr   Ú_recommendation_engine)Úselfr   r   r   © r-   ú/var/www/snowflake_co_dev_github/snow_flake_back_end_deploy/mama_care_api/ali_express_ds/pms/engine/services/decision_engine.pyÚ__init__   s   
zDecisionEngine.__init__c              
   C  s®   | j  | j¡}| j | j¡}|  |¡}|jdkr|jnd}|  ||¡}|  |¡}| j |||¡}| j	 |||¡}| j
 |||¡}	| j ||||||	¡}
|  |||||||	|
¡S )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Úrecommendationr-   r-   r.   Úrun4   s    

ÿþzDecisionEngine.runr9   ú'float | None'Ústore_scoreúlist[SkuDecision]c                 C  s^   |   ¡ }|  |¡}g }|D ]}tt|ddd�ƒ}| | jj|| j |¡| j	|||d�¡ q|S )N)Úsku_idÚskuIdÚidÚ ©Údefault)Úsku_dtoÚfreight_jsonr   r9   rC   Úmax_supplier_price)
Ú_extract_sku_dtosÚ_max_supplier_priceÚstrr	   Úappendr'   r0   r#   Úgetr$   )r,   r9   rC   Úsku_dtosrM   Ú	decisionsrK   rE   r-   r-   r.   r3   K   s    

úÿ
zDecisionEngine._analyze_skusc                 C  s   t | jdƒ}dd„ t|ƒD ƒS )N)z,ae_item_sku_info_dtos.ae_item_sku_info_d_t_oÚae_item_sku_info_dtosÚsku_info_dtosÚskusc                 S  s   g | ]	}t |tƒr|‘qS r-   )Ú
isinstancer   ©Ú.0Údtor-   r-   r.   Ú
<listcomp>e   s    z4DecisionEngine._extract_sku_dtos.<locals>.<listcomp>)r	   r!   r   )r,   Ú	containerr-   r-   r.   rN   _   s
   þz DecisionEngine._extract_sku_dtosrS   c                   s$   t ƒ ‰ ‡ fdd„| D ƒ}t|dd�S )z9Anchor used to compare SKU prices against their siblings.c                   s   g | ]}ˆ   |¡j‘qS r-   )r0   Úsupplier_pricerY   ©Úanalyzerr-   r.   r\   k   s    z6DecisionEngine._max_supplier_price.<locals>.<listcomp>ç        rI   )r   Úmax)rS   Úpricesr-   r_   r.   rO   g   s   z"DecisionEngine._max_supplier_priceúdict[str, dict]c                 C  sP   i }| D ]!}t |tƒsqtt|ddd�ƒ}t|dƒ}|r%t |tƒr%|||< q|S )N)rF   rE   rH   rI   )ÚfreightJsonrL   Úfreight)rX   r   rP   r	   )r   ÚindexÚentryrE   rf   r-   r-   r.   r"   n   s   

€zDecisionEngine._index_freightrT   údict[str, Optional[str]]c                   s„   ˆ s	dd„ dD ƒS dd‡ fd	d
„}|dd„ ƒ|dd„ dd�|dd„ ƒ|dd„ ƒ|dd„ ƒ|dd„ dd�|dd„ ƒ|dd„ dd�dœS )zDFind the winner per business dimension. ``None`` when no SKU exists.c                 S  s   i | ]}|d “qS r    r-   )rZ   Úkeyr-   r-   r.   Ú
<dictcomp>�   s    z-DecisionEngine._rank_skus.<locals>.<dictcomp>)ÚbestOverallSkuÚlowestCostSkuÚhighestProfitSkuÚhighestMarginSkuÚhighestStockSkuÚfastestDeliverySkuÚbestValueSkuÚlowestShippingCostSkuTÚreverseÚboolr   rP   c                   s   t ˆ | |d�d }|jjS )N)rj   rt   r   )ÚsortedÚskurE   )Úkey_fnrt   Úbest©rT   r-   r.   Úwinner‡   s   z)DecisionEngine._rank_skus.<locals>.winnerc                 S  ó   | j jS r    ©Úresultr2   ©Údr-   r-   r.   Ú<lambda>Œ   ó    z+DecisionEngine._rank_skus.<locals>.<lambda>c                 S  r|   r    )ÚpricingÚ
total_costr   r-   r-   r.   r�   �   r‚   F)rt   c                 S  r|   r    )rƒ   Úestimated_profitr   r-   r-   r.   r�   Ž   r‚   c                 S  r|   r    )rƒ   Úmarginr   r-   r-   r.   r�   �   r‚   c                 S  r|   r    )rw   Ústockr   r-   r-   r.   r�   �   r‚   c                 S  s   | j jd ur
| j jS dS )Ng     8�@)rf   Údelivery_days_avgr   r-   r-   r.   r�   ’   s   ÿc                 S  s    | j jdkr| jj| j j S dS )Nr   ra   )rƒ   r„   r~   r2   r   r-   r-   r.   r�   ˜   s   ÿc                 S  r|   r    )rf   Úshipping_costr   r-   r-   r.   r�   œ   r‚   N)T)rt   ru   r   rP   r-   )rT   r{   r-   rz   r.   r4   }   s&   



ýÿÿðzDecisionEngine._rank_skusr7   r   c                 C  s@   | j dkr| jdkrdS tt| j tjƒd t| jtjƒd  ƒS )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)r7   r-   r-   r.   r1   £   s   ÿÿÿÿz DecisionEngine._popularity_scorer;   r<   c	           
      C  sö   |r
t |dd„ d�nd }	i d|j“dt|jƒ“dt|jƒ“d|	r'|	jjdd	œnd “d
|“d| ¡ “d|	r9|	j ¡ nd “d| ¡ “d| ¡ “dt|jdƒ|j	oWdd„ |j	 
¡ D ƒdœ“ddd„ |D ƒ“d|j“d|j“d|j“d|j“d|j“d|j“S )Nc                 S  r|   r    r}   r   r-   r-   r.   r�   Â   r‚   z0DecisionEngine._build_response.<locals>.<lambda>)rj   ÚdecisionÚ
confidenceÚoverallScoreÚbestSkuzHighest overall score)rF   Úreasonr<   r=   rƒ   r8   r7   Úscoresr   c                 S  s   i | ]
\}}|t |d ƒ“qS )r   )Úround)rZ   ÚkÚvr-   r-   r.   rk   Õ   s    ÿz2DecisionEngine._build_response.<locals>.<dictcomp>)ÚoverallÚ	breakdownÚskuAnalysisc                 S  s   g | ]}|  ¡ ‘qS r-   )Úto_dict)rZ   r€   r-   r-   r.   r\   Ø   s    z2DecisionEngine._build_response.<locals>.<listcomp>Ú	strengthsÚrisksÚsummaryÚconfidenceReasonsÚmarketRecommendationÚskuRecommendation)rb   r�   r•   r�   Úoverall_scorerw   rE   r›   rƒ   Úscore_breakdownÚitemsrœ   r�   rž   Úconfidence_reasonsÚmarket_recommendationÚsku_recommendation)
r,   r7   r8   r;   r<   r=   r>   r?   r@   ry   r-   r-   r.   r6   ¶   s`   ÿþÿ
þ
ýÿúø	÷
öõô
ÿýóíìëêéèçzDecisionEngine._build_responseN)r   r   r   r   r   r   r   r   )r   r   )r9   rB   rC   rB   r   rD   )r   r   )rS   r   r   r   )r   r   r   rd   )rT   rD   r   ri   )r7   r   r   rB   )r;   rD   r<   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r/   rA   r3   rN   ÚstaticmethodrO   r"   r4   r1   r6   r-   r-   r-   r.   r      s    



%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-   r-   r-   r.   Ú<module>   s    	