
    !+i                         d Z ddlZddlmZmZmZ ddlmZ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  ej&                  e      Z G d d      Zy)zU
Hyper Forecast - Main Engine
Combines all multipliers to generate sales predictions
    N)datetimedate	timedelta)DictListOptional)Session   )DataCollector)BaselineCalculator)CalendarMultipliers)MomentumCalculatorc                      e Zd ZdZdefdZ	 	 ddedee   dee	   de
fd	Zdeded
ede
dedee
   fdZ	 ddedededede
dee   defdZ	 	 ddedee   dee	   de
fdZ	 	 ddee   dee	   de
fdZde
fdZddee   de
fdZde
fdZy)HyperForecastuU  
    Main forecasting engine that combines ALL prediction factors.
    
    Uses DynamicMultipliers to load ALL factors from database.
    No hardcoded factors - everything is configurable.
    
    Formula: PREDICTION = Σ(products) where each product uses:
      base_units × global_multipliers × product_multipliers × stock_factor
    dbc                     || _         t        |      | _        t        |      | _        t               | _        t        |      | _        ddl	m
}  ||      | _        y )Nr
   )DynamicMultipliers)r   r   data_collectorr   baseline_calcr   calendar_multr   momentum_calcmultipliers.dynamicr   dynamic_mult)selfr   r   s      J/var/www/hypershopcomercio.com.br/hyper-ai/app/services/forecast/engine.py__init__zHyperForecast.__init__   sM    +B//302/3 	<.r2    Ntarget_hourtarget_datecategoryreturnc                 *   |"t        j                         j                         }t        j                         }||j                         kD  xs$ ||j                         k(  xr ||j                  kD  }| j                  j                  ||      }i }i }|j                         D ]
  \  }	}
|
||	<    |rU||j                         k(  rB| j                  j                         }|d   |d<   |d   }|j                  dd      |d<   ||d<   nd|d<   d	}d|d<   | j                  j                  ||      }|d
   }|d   }| j                  j                  |      }| j                  |||||      }|r$|d   }|d   }|d   }|d   }t        |d      |d<   n||z  }|}g }d|d<   d}|j                         D ]  }||z  }	 t!        d |j                         D              }|dk  rd}d}n|dk  rd}d}n|dk  rd}d}nd}d}||z  }|d|z
  z  }|d|z   z  }||dd|j#                         t        |d      t        |d      t        |d      t        |d      t        |d      t        |d      t        |d      ||t%        |j'                               d|dd  |d!S )"a  
        Generate prediction for a specific hour using product-based forecasting.
        
        IMPORTANT: This method applies ALL available factors without bias.
        The data collected will determine which factors have the most impact.
        
        Factors applied:
        - Global: day_of_week, period_of_month, event, seasonal, momentum
        - Per-product: trend, category (seasonal), stock (physical constraint)
        
        Args:
            target_hour: Hour (0-23) to predict
            target_date: Date to predict (defaults to today)
            category: Optional product category filter
        
        Returns:
            Dict with prediction, factor breakdown, AND product mix
        N
multipliermomentumreason	directionneutralmomentum_reason      ?normalbaseline
confidencetotal_revenuepotential_revenueproduct_mixstock_factor   stockc              3   8   K   | ]  }t        |d z
          yw)r)   N)abs).0ms     r   	<genexpr>z-HyperForecast.predict_hour.<locals>.<genexpr>   s     Ns1s7|Ns   g333333?g?g333333?g333333?gffffff?g?g?      ?r
   02dh   )r(   multiplier_typesd   )hour
hour_labelr   
predictionprediction_potentialminmaxr,   r+   combined_multipliermultipliersfactorsr/   	is_future)r   nowr   r>   r   get_all_global_multipliersitemsr   calculate_momentumgetr   calculate_baselinecalculate_combined_multiplier_calculate_product_based_hourlyroundvaluessum	isoformatlistkeys)r   r   r   r    rH   rG   raw_multipliersall_multipliersfactor_metadatakvmomentum_resultr(   baseline_resultr+   baseline_confidenceglobal_multiplierproduct_basedr@   potential_predictionr/   r0   rD   multdeviation_factorconfidence_rangeconfidence_levelfinal_confidencemin_predictionmax_predictions                                 r   predict_hourzHyperForecast.predict_hour(   sA   0 ",,.--/Klln 388:-h;#((*3L3gQ\_b_g_gQg	 ++FF{T_`#))+ 	#DAq!"OA	# 
2"00CCEO*9,*GOJ'-h7O*9*=*=k9*UOJ'1@O-.*-OJ'&O*3OJ' ,,??[Y":.-l; !--KKO\ <<&7#
 &7J#01D#E '6K(8L (-\1'=OG$ "$55J#- K'*OG$ "#**, 	(D4'	( N_5K5K5MNNc!##########+.AA#q+;';<#q+;';<  (-Q/))+
A.$)*>$B++ 0!4h*#()<a#@*#2$()=)=)?$@ 't,"#
 	
r   r^   global_factorsrH   c                    	 ddl m} ddlm} | j                  j                  |      j                  |j                  dk(        j                         }|syd}	d}
g }|D ]  }t        |j                  xs d      }|dz  }t        |j                  xs d      }|j                  xs d}|dk  rQ||z  }| j                  j                  |      }| j                  j                  |      }|j!                  d	d      }|dk(  rd}nC|j"                  r7t        |j"                        d
k  rt%        t        |j"                        |      }||j!                  d	d      xs dz  }||z  |z  }||z  }||z  }||z  }|	|z  }	|
|z  }
d}||j'                         k  s"||j'                         k(  rH||j(                  k  r9| j*                  j-                  |j.                  ||      }|j!                  dd      }|dkD  s|dkD  s|dkD  s|j1                  |j.                  |j2                  xs dt5        |d      t5        |d      t5        |d      t5        |d      t5        |d      |||t5        |d      |j6                  d       " |j9                  d d       |
dkD  r|	|
z  nd}|	|
||dS # t:        $ r"}t<        j?                  d|        Y d}~yd}~ww xY w)z
        Calculate hourly prediction based on individual products.
        Returns total revenue, potential revenue, and product mix.
        r   ProductForecastget_category_multiplierTN           r)   stock_pressurer
   units   ?   r;   r1   )mlb_idtitleunits_expectedunits_potentialrevenue_expectedrevenue_potential
base_unitsrealized_unitsr2   product_multiplierscombined_product_multcurvec                     | d   S )Nrz    xs    r   <lambda>z?HyperForecast._calculate_product_based_hourly.<locals>.<lambda>  s    1-?+@ r   keyreverse)r-   r.   r0   r/   z4[FORECAST] Product-based hourly calculation failed: ) app.models.product_forecastrl   app.jobs.category_syncrn   r   queryfilter	is_activeallfloatavg_units_7dpricestock_currentr   get_all_product_multipliersrN   rL   days_of_coveragerB   r   r>   r   get_hourly_sales_by_productrv   appendrw   rP   r   sort	Exceptionloggerwarning)r   r   r   r^   ri   rH   rl   rn   productsr-   r.   r/   pbase_units_dailybase_units_hourlyr   r2   units_adjustedr~   product_multr0   product_mult_no_stockunits_finalry   revenuerev_potentialr}   
real_salesoverall_stock_factores                                 r   rO   z-HyperForecast._calculate_product_based_hourly   s   g	CFww}}_5<<))T1ce  M #K G#()<1#= $4r$9!aggl+,1 3; "35F!F '+&7&7&S&STU&V#  $00NNObc  3667GMA:#&L''E!2D2D,E,I#&uQ-?-?'@,#OL )58K8O8OP`be8f8mjm(n% -/DD|S"03H"H%- /% 7(!]2! "#+sxxz0Ik]`]e]eNe #'"5"5"Q"QRSRZRZ\git"uZ&0nnWa&@^Q;-!"3~7I&&"#((!"C*/Q*?+0!+D,1'1,=-2=!-D&+,=q&A*8!&/B16|Q1G!"( uGT !@$O IZ\]H]=3D#Dcf  "/%6 4*	   	NNQRSQTUV	s&   AJ( F*J( B%J( (	K1KKr@   r+   rE   r/   c           	      p   	 ddl m} t        j                  |t        j                  j                               j                  |      }|t        d      z   }	| j                  j                  |      j                  |j                  |k\  |j                  |	k        j                         }
d}|
D ]5  }|j                  |j                  }| j                  j                  |       7 |r|dd |d<    |t        j                         |||||d	
      }| j                  j!                  |       | j                  j#                          t$        j'                  d| d|d       |j(                  S # t*        $ r<}t$        j-                  d|        | j                  j/                          Y d}~yd}~ww xY w)z
        Log prediction to forecast_logs table for future learning
        
        Returns:
            ID of the created log entry
        r   ForecastLog)r>   r
   )hoursNr=   _product_mixheuristic_v1)timestamp_previsao	hora_alvovalor_previsto
valor_realfatores_usadosbaseline_usadomodelo_versaoz![FORECAST] Logged prediction for z: R$.2fz%[FORECAST] Failed to log prediction: )app.models.forecast_learningr   r   combinerB   timereplacer   r   r   r   r   r   r   deleteutcnowaddcommitr   debugidr   r   rollback)r   r   r   r@   r+   rE   r/   r   r   	next_hourexisting_logsreal_value_to_preserveold_log	log_entryr   s                  r   _log_predictionzHyperForecast._log_prediction.  s   2	@ ((hll6G6G6IJRRXcRdI "IA$66I !GGMM+6==%%2%%	1 ce 
 &*"( (%%1-4-?-?* w'( .9$3.?N+##+??#4#)1*',I GGKK	"GGNNLL<YKtJWZK[\]<< 	NNB1#FGGG	s   E-E0 0	F592F00F5c           
         | j                  |||      }|duxs |d   }|r|d   j                         }| j                  j                         }|j	                         D ]  \  }}	|	|d| <    d|v rd|d   v r|d   d   |d<   | j                  |xs" t        j                         j                         ||d   |d	   ||j                  d
            }
|
|d<   |S )z
        Generate prediction AND log it for learning system
        Use this method when you want predictions to be tracked
        NrG   rE   _meta_rF   r(   _info_momentum_reasonr@   r+   r/   )r   r   r@   r+   rE   r/   log_id)
rh   copyr   get_factor_metadatarJ   r   r   rH   r   rL   )r   r   r   r    result
should_logmultipliers_to_logrX   factor_namecategorical_keyr   s              r   predict_hour_with_loggingz'HyperForecast.predict_hour_with_loggingq  s    "";XF
 !,C{0C
!'!6!;!;!= #//CCEO 1@0E0E0G M,_=L"VK=#9:M F"'8F9<M'M>DY>OPa>b"#:;))'@8<<>+>+>+@'!,/
+."JJ}5 * F  &F8r   c           
         |"t        j                         j                         }g }d}d}d}d}t        d      D ]F  }| j	                  |||      }	|j                  |	       ||	d   z  }||	d   z  }||	d   z  }||	d   z  }H t        |d       }
t        |d	       }|j                         t        |d
      t        |d
      t        |d
      t        |dz  d
      ||
d   |
d   d|d   |d   ddS )zG
        Generate predictions for an entire day (all 24 hours)
        r   rp   r@   rB   rC   r,   c                     | d   S Nr@   r   r   s    r   r   z+HyperForecast.predict_day.<locals>.<lambda>  s
    Q|_ r   )r   c                     | d   S r   r   r   s    r   r   z+HyperForecast.predict_day.<locals>.<lambda>  s
    q r   r;   r?   )r>   r@   )r   total_predicted	total_min	total_maxavg_confidencehourly	peak_hourvalley_hour)
r   rH   r   rangerh   r   rC   rB   rS   rP   )r   r   r    hourly_predictionsr   r   r   r   r>   predpeakvalleys               r   predict_dayzHyperForecast.predict_day  s9    ",,.--/K		"I 	1D$$T;AD%%d+tL11Oe$Ie$Id<00N	1 %+DE'-FG  ))+$_a8y!,y!,#NR$7;(\*"<0
 |,$\2
 	
r   c                   
 t        j                         j                         }t        j                         j                  
| j	                  |      }| j
                  j                         }t        d |D              }| j
                  j                  |d      }t        d |D              }t        
fd|d   D              }||z   }|dkD  r||z
  |z  dz  nd}	|j                         
t        |d      t        |d      t        |d      t        |t        
fd	|d   D              z   d      t        |t        
fd
|d   D              z   d      t        |d      t        |	d      |d   ||d   |d|d   |d   dS )zn
        Get today's forecast combined with actual sales data
        Perfect for the dashboard chart
        c              3   &   K   | ]	  }|d      ywr   Nr   r5   r:   s     r   r7   z7HyperForecast.get_today_with_actuals.<locals>.<genexpr>  s     9A1Y<9   weekc              3   &   K   | ]	  }|d      ywr   r   r   s     r   r7   z7HyperForecast.get_today_with_actuals.<locals>.<genexpr>  s     <aQy\<r   c              3   8   K   | ]  }|d    kD  r|d     yw)r>   r@   Nr   r5   r   current_hours     r   r7   z7HyperForecast.get_today_with_actuals.<locals>.<genexpr>  s)      "
y<' lO"
s   r   r   r=   r;   c              3   :   K   | ]  }|d    kD  s|d     yw)r>   rB   Nr   r   s     r   r7   z7HyperForecast.get_today_with_actuals.<locals>.<genexpr>  $     5{1bcdjbknzbzah5{   
c              3   :   K   | ]  }|d    kD  s|d     yw)r>   rC   Nr   r   s     r   r7   z7HyperForecast.get_today_with_actuals.<locals>.<genexpr>  r   r   r
   r   )actualspredictionspreviousr   r   )r   r   actual_totalremaining_predictedprojected_totalprojected_minprojected_maxprevious_period_totalvs_previous_percentr   r   r   r   )r   rH   r   r>   r   r   get_sales_today_so_farrR   get_sales_previous_periodrS   rP   )r   todayday_forecastr   r   r   previous_totalr   r   r   r   s             @r   get_today_with_actualsz$HyperForecast.get_today_with_actuals  s   
 ##%||~** ''. %%<<>999 &&@@O<8<< " "
!(+"
 
 ')<< ^lno]o. @NRUXXuv OO%(!,2#()<a#@$_a8"<#5{U]H^5{2{#{}~"<#5{U]H^5{2{#{}~%*>1%=#()<a#@*+;<"+H5$
 &k2'6#
 	
r   c                 \	   	 ddl m} |"t        j                         j	                         }| j
                  j                  |      j                  |j                  dk(        j                         }|st        j                  d       yd}d}d}d}g }| j                  j                  |d      }	t        j                         }
||
j	                         k(  r | j                  j                         }|d   }nd}|	d	   |	d
   |	d   |	d   |d}d}|j!                         D ]  }||z  }	 |D ]  }t#        |j$                  xs d      }t#        |j&                  xs d      }|j(                  xs d}i }|j*                  dk(  r2|j,                  r&dt/        t#        |j,                        dz  d      z   }nC|j*                  dk(  r2|j,                  r&dt1        t#        |j,                        dz  d      z   }nd}t3        |d      |d<   	 ddlm}  || j
                  |j8                        }t3        |d      |d<   |dk(  rd}|dz  }nF|j<                  r3t#        |j<                        dk  rt#        |j<                        }|dz  }nd}|dz  }t3        |d      |d<   ||z  }||z  |z  }||z  }||z  }||z  }||z  }||z  }|dkD  s|dkD  s|j?                  i d|j@                  d|jB                  r|jB                  dd nddt3        |d      dt3        |d      d t3        |d      d!|d|d"|jD                  xs dd#|jF                  xs dd$|jH                  xs dd%t#        |j<                  xs d      d&|d'|d(t3        |d      d)t3        |d      d*t3        ||z
  d      d+|jJ                          ||z
  }|dkD  r||z  dz  nd}|jM                  d, d-       t        jO                  d.|d/d0|d/d1       |jQ                         d2t3        |d      t3        |d      t3        |d      t3        |d      |t3        |d      |||dd3 d4d5S # t:        $ r d}Y ?w xY w# t:        $ r6} t        jS                  d6|         ddl*}!|!jW                          Y d} ~ yd} ~ ww xY w)7u  
        Get forecast based on sum of individual product forecasts.
        
        IMPORTANT: Apply ALL available factors without bias.
        The data collected will determine which factors have the most impact.
        We should NOT cherry-pick factors - let the data speak.
        
        Factors applied per product:
        - Base units (from historical avg_units_7d)
        - ALL calendar multipliers (day_of_week, period_of_month, event, seasonal)
        - Momentum (if available)
        - Stock factor (physical constraint - no stock = no sales)
        - Category factor (when category_mapping is populated)
        - Product trend (up/down based on recent performance)
        
        Formula: units = avg_units × Π(ALL_FACTORS) × stock_factor
        Revenue = units × price
        
        Returns:
            Dict with total forecast, all factors applied, and breakdown by product
        r   rk   NTzJ[FORECAST] No products in product_forecast table, falling back to baselinero   r#   r)   day_of_weekperiod_of_montheventseasonal)r  r  r  r  r$   upr=   r8   downg      r1   trendrm   r    r
   r2   2   rv   rw   rt   	avg_unitsr;   r   final_unitsr   
stock_fullstock_localstock_incomingr   ri   product_factorsforecast_valuepotential_valuelost_revenuer   c                     | d   S )Nr  r   r   s    r   r   z:HyperForecast.get_product_based_forecast.<locals>.<lambda>  s    +;)< r   r   z%[FORECAST] Product-based forecast: R$r   z	 (lost R$z due to stock)product_based_v2   zQAll available factors applied without bias. Data will determine impact over time.)r   methodtotal_forecasttotal_potentiallost_to_stockstock_impact_pctri   r^   products_with_stockproducts_without_stock	breakdown_notez,[FORECAST] Error in product-based forecast: ),r   rl   r   rH   r   r   r   r   r   r   r   r   r   get_all_calendar_multipliersr   rK   rQ   r   r   r   r   r
  	trend_pctrB   rC   rP   r   rn   category_mlr   r   r   rv   rw   r  r  r  r   r   inforS   error	traceback	print_exc)"r   r   rl   r   r  total_if_all_stockr  r  r  calendarrH   r[   momentum_multall_global_factorsr^   factorr   r|   r   r2   r  trend_factorrn   category_factorr0   product_multiplierr   r  product_forecast_valuefull_potentialr  r  r   r&  s"                                     r   get_product_based_forecastz(HyperForecast.get_product_based_forecast  s|   ,d	C"&lln113 ww}}_5<<))T1ce  kl N!$"#%&"I ))FF{TXYH ,,.Cchhj("&"4"4"G"G"I / = #  (6#+,=#>!'*$Z0)" !$,335 ,!V+!,  T
 #1>>#6Q7
aggl+,1 #% 77d?q{{#&U1;;-?#-Es)K#KLWW&1;;#&U1;;-?#-Et)L#LL#&L+0q+A(*N&=dggq}}&UO /4OQ.G
+ A:#&L*a/*''E!2D2D,E,I#(););#<L*a/*#&L'1,'+0q+A( &2O%C" ",.?!?BT!T -|; *5u)<&!/%!7"88"n4" *A-"1D$$ & !((&"c& $U:q%9& )%*B	&
 &u[!'<&  &  & %all&7a& &q}}'9& )!*:*:*?a& +E!2D2D2I,J& )*<& *?& )%0F*J& *5+C&  'n?U.UWX(Y!&"  #& ETn .>LL^abLb/A AC Ghi NN<dNKKK?s?SS\]ijm\nn|}~ $--/,"'":#();Q#?!&|Q!7$)*:A$>"4%*+<a%@':*@&s^l I ! *&)O*f  	LLGsKL!		sK   BQ, 	E<Q, #Q)B!Q, FQ, Q)%Q, (Q))Q, ,	R+5,R&&R+c                    	 ddl m} t        j                         }| j                  j                  |      j                  |j                  j                  d      |j                  |k        j                         }d}d}|D ]  }| j                  j                  |j                  j                         |j                  j                        }|d   }||_        |dkD  r%t        |j                   xs d      }	|	|z
  |z  dz  }
n!t        |j                   xs d      dkD  rd}
nd}
|
dkD  rd}
n|
d	k  rd	}
t#        |
d
      |_        |t'        |
      z  }|dz  } | j                  j)                          |dkD  r||z  nd}|t#        |d
      dS # t*        $ r9}t,        j/                  d|        | j                  j1                          |d}~ww xY w)zH
        Reconcile pending forecast logs with actual sales data
        r   r   Nro   r   r=   g      Y@gR?@gR?r;   r
   )
reconciledavg_abs_errorz)[FORECAST] Errors during reconciliation: )r   r   r   rH   r   r   r   r   is_r   r   r   get_hourly_salesr   r>   r   r   rP   erro_percentualr4   r   r   r   r%  r   )r   r   rH   pending_logsprocessed_counttotal_errorlogactual_dataactual_revenuepredicted_valr%  r5  r   s                r   reconcile_predictionsz#HyperForecast.reconcile_predictions  s   :	@ ,,.C77==5<<&&**40%%+ ce 
  OK# %"11BB3==CUCUCWY\YfYfYkYkl!,Y!7 "0 "A% %*#*<*<*A$BM+n<NRUUE3--23a7 #UE 6>"EW_#E&+E1o#s5z)1$=%@ GGNN?NQR?R[?:XYM .!&}a!8 
  	LLDQCHIGGG	s   F
F 	G4G

G)NN)N)__name__
__module____qualname____doc__r	   r   intr   r   strr   rh   r   r   rO   r   r   r   r   r  r2  r@  r   r   r   r   r      s   	37 	3 '+"&	O
O
 d^O
 3-	O

 
O
bss s !	s
 s s 
$sx '+AA A 	A
 A A d^A 
AL '+"&	** d^* 3-	*
 
*\ '+"&,
d^,
 3-,
 
	,
\2
 2
hzhtn zPT zx>t >r   r   )rD  loggingr   r   r   typingr   r   r   sqlalchemy.ormr	   r   r   r+   r   multipliers.calendarr   multipliers.momentumr   	getLoggerrA  r   r   r   r   r   <module>rM     sH     . . ' ' " ) ( 5 4			8	$g gr   