OZON Price Optimizer with Competitor Analysis

Analyzes competitor prices from search queries and suggests optimal pricing using Bayesian methods and AI to maximize profit

Size

157.4 KB

Version

2.1.70

Created

Jan 12, 2026

Updated

3 months ago

1// ==UserScript==
2// @name		OZON Price Optimizer with Competitor Analysis
3// @description		Analyzes competitor prices from search queries and suggests optimal pricing using Bayesian methods and AI to maximize profit
4// @version		2.1.70
5// @match		https://*.ozon.ru/*
6// @icon		https://st.ozone.ru/assets/favicon.ico
7// @grant		GM.getValue
8// @grant		GM.setValue
9// @grant		GM.xmlhttpRequest
10// @require		https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js
11// ==/UserScript==
12(function() {
13    'use strict';
14
15    console.log('🚀🚀🚀 OZON PRICE OPTIMIZER VERSION 2.0.1 LOADED 🚀🚀🚀');
16
17    // Product data mapping (артикул -> себестоимость, комиссия, доставка)
18    const PRODUCT_DATA = {
19'1740824669': { cost: 146.4, commission: 0.39, delivery: 105 },
20        '1157786755': { cost: 159.6, commission: 0.39, delivery: 105 },
21        '1126896590': { cost: 111.6, commission: 0.39, delivery: 105 },
22        '1643994739': { cost: 242.4, commission: 0.39, delivery: 105 },
23        '1672597444': { cost: 130.8, commission: 0.39, delivery: 105 },
24        '1220422423': { cost: 115.2, commission: 0.39, delivery: 105 },
25        '1791969680': { cost: 258, commission: 0.39, delivery: 105 },
26        '1134301258': { cost: 117.6, commission: 0.39, delivery: 105 },
27        '881812095': { cost: 219.6, commission: 0.39, delivery: 105 },
28        '476573272': { cost: 198, commission: 0.39, delivery: 105 },
29        '1091687376': { cost: 133.2, commission: 0.39, delivery: 105 },
30        '1865971423': { cost: 213.6, commission: 0.39, delivery: 105 },
31        '1091884893': { cost: 115.2, commission: 0.39, delivery: 105 },
32        '1509173668': { cost: 146.4, commission: 0.39, delivery: 105 },
33        '1643957952': { cost: 154.8, commission: 0.39, delivery: 105 },
34        '1615018099': { cost: 216, commission: 0.39, delivery: 105 },
35        '1149665681': { cost: 92.4, commission: 0.39, delivery: 105 },
36        '1042512806': { cost: 118.8, commission: 0.39, delivery: 105 },
37        '1586302587': { cost: 200.4, commission: 0.39, delivery: 105 },
38        '1915136286': { cost: 199.2, commission: 0.39, delivery: 105 },
39        '1061692407': { cost: 188.4, commission: 0.39, delivery: 105 },
40        '907545404': { cost: 199.2, commission: 0.39, delivery: 105 },
41        '701748607': { cost: 124.8, commission: 0.39, delivery: 105 },
42        '1464498458': { cost: 147.6, commission: 0.39, delivery: 105 },
43        '1423324644': { cost: 117.6, commission: 0.39, delivery: 105 },
44        '847234813': { cost: 146.4, commission: 0.39, delivery: 105 },
45        '1644305207': { cost: 236.4, commission: 0.39, delivery: 105 },
46        '1220412279': { cost: 110.4, commission: 0.39, delivery: 105 },
47        '1440280204': { cost: 172.8, commission: 0.39, delivery: 105 },
48        '881841274': { cost: 182.4, commission: 0.39, delivery: 105 },
49        '881911476': { cost: 162, commission: 0.39, delivery: 105 },
50        '1558183265': { cost: 151.2, commission: 0.39, delivery: 105 },
51        '442408015': { cost: 213.6, commission: 0.39, delivery: 105 },
52        '1323322968': { cost: 175.2, commission: 0.39, delivery: 105 },
53        '524540150': { cost: 138, commission: 0.39, delivery: 105 },
54        '1648863445': { cost: 172.8, commission: 0.39, delivery: 105 },
55        '1646939718': { cost: 157.2, commission: 0.39, delivery: 105 },
56        '1205194839': { cost: 153.6, commission: 0.39, delivery: 105 },
57        '645226241': { cost: 158.4, commission: 0.39, delivery: 105 },
58        '2007243137': { cost: 291.6, commission: 0.39, delivery: 105 },
59        '1421135622': { cost: 91.2, commission: 0.39, delivery: 105 },
60        '701884874': { cost: 116.4, commission: 0.39, delivery: 105 },
61        '1421119246': { cost: 158.4, commission: 0.39, delivery: 105 },
62        '2007259608': { cost: 307.2, commission: 0.39, delivery: 105 },
63        '359062751': { cost: 122.4, commission: 0.39, delivery: 105 },
64        '1005718040': { cost: 158.4, commission: 0.39, delivery: 105 },
65        '906225589': { cost: 96, commission: 0.39, delivery: 105 },
66        '1556242664': { cost: 680.4, commission: 0.39, delivery: 105 },
67        '1064594212': { cost: 148.8, commission: 0.39, delivery: 105 },
68        '799768912': { cost: 122.4, commission: 0.39, delivery: 105 },
69        '1739604132': { cost: 217.2, commission: 0.39, delivery: 105 },
70        '1062956956': { cost: 136.8, commission: 0.39, delivery: 105 },
71        '645221613': { cost: 144, commission: 0.39, delivery: 105 },
72        '259307672': { cost: 154.8, commission: 0.39, delivery: 105 },
73        '1739610762': { cost: 214.8, commission: 0.39, delivery: 105 },
74        '261137335': { cost: 130.8, commission: 0.39, delivery: 105 },
75        '1134258903': { cost: 120, commission: 0.39, delivery: 105 },
76        '1354364340': { cost: 140.4, commission: 0.39, delivery: 105 },
77        '583903282': { cost: 105.6, commission: 0.39, delivery: 105 },
78        '1210396815': { cost: 152.4, commission: 0.39, delivery: 105 },
79        '840692395': { cost: 140.4, commission: 0.39, delivery: 105 },
80        '1428754652': { cost: 117.6, commission: 0.39, delivery: 105 },
81        '830793833': { cost: 141.6, commission: 0.39, delivery: 105 },
82        '645231878': { cost: 122.4, commission: 0.39, delivery: 105 },
83        '1638790412': { cost: 147.6, commission: 0.39, delivery: 105 },
84        '1594351493': { cost: 148.8, commission: 0.39, delivery: 105 },
85        '1556059491': { cost: 472.8, commission: 0.39, delivery: 105 },
86        '1652932872': { cost: 166.8, commission: 0.39, delivery: 105 },
87        '1220450238': { cost: 141.6, commission: 0.39, delivery: 105 },
88        '601543246': { cost: 133.2, commission: 0.39, delivery: 105 },
89        '907613435': { cost: 156, commission: 0.39, delivery: 105 },
90        '528451380': { cost: 109.2, commission: 0.39, delivery: 105 },
91        '645231366': { cost: 111.6, commission: 0.39, delivery: 105 },
92        '1583090470': { cost: 211.2, commission: 0.39, delivery: 105 },
93        '645344262': { cost: 217.2, commission: 0.39, delivery: 105 },
94        '1427430872': { cost: 135.6, commission: 0.39, delivery: 105 },
95        '308474502': { cost: 135.6, commission: 0.39, delivery: 105 },
96        '1034686951': { cost: 110.4, commission: 0.39, delivery: 105 },
97        '1635265452': { cost: 164.4, commission: 0.39, delivery: 105 },
98        '1181294718': { cost: 136.8, commission: 0.39, delivery: 105 },
99        '907477992': { cost: 111.6, commission: 0.39, delivery: 105 },
100        '275785773': { cost: 105.6, commission: 0.39, delivery: 105 },
101        '415116965': { cost: 129.6, commission: 0.39, delivery: 105 },
102        '885661840': { cost: 132, commission: 0.39, delivery: 105 },
103        '1138405158': { cost: 123.6, commission: 0.39, delivery: 105 },
104        '1474598641': { cost: 153.6, commission: 0.39, delivery: 105 },
105        '1749441319': { cost: 156, commission: 0.39, delivery: 105 },
106        '983496770': { cost: 180, commission: 0.39, delivery: 105 },
107        '259307514': { cost: 121.2, commission: 0.39, delivery: 105 },
108        '1412471842': { cost: 147.6, commission: 0.39, delivery: 105 },
109        '2007285388': { cost: 260.4, commission: 0.39, delivery: 105 },
110        '753545450': { cost: 105.6, commission: 0.39, delivery: 105 },
111        '414662752': { cost: 145.2, commission: 0.39, delivery: 105 },
112        '906537851': { cost: 120, commission: 0.39, delivery: 105 },
113        '745134928': { cost: 120, commission: 0.39, delivery: 105 },
114        '1450813313': { cost: 171.6, commission: 0.39, delivery: 105 },
115        '815579726': { cost: 108, commission: 0.39, delivery: 105 },
116        '1554889144': { cost: 172.8, commission: 0.39, delivery: 105 },
117        '1317529509': { cost: 108, commission: 0.39, delivery: 105 },
118        '1412482622': { cost: 201.6, commission: 0.39, delivery: 105 },
119        '711457941': { cost: 116.4, commission: 0.39, delivery: 105 },
120        '746323388': { cost: 166.8, commission: 0.39, delivery: 105 },
121        '1678615312': { cost: 144, commission: 0.39, delivery: 105 },
122        '1261461822': { cost: 93.6, commission: 0.39, delivery: 105 },
123        '601551066': { cost: 144, commission: 0.39, delivery: 105 },
124        '1440304060': { cost: 218.4, commission: 0.39, delivery: 105 },
125        '1363004944': { cost: 132, commission: 0.39, delivery: 105 },
126        '583586841': { cost: 162, commission: 0.39, delivery: 105 },
127        '701743635': { cost: 112.8, commission: 0.39, delivery: 105 },
128        '483752519': { cost: 114, commission: 0.39, delivery: 105 },
129        '254240996': { cost: 110.4, commission: 0.39, delivery: 105 },
130        '711403910': { cost: 105.6, commission: 0.39, delivery: 105 },
131        '701745855': { cost: 111.6, commission: 0.39, delivery: 105 },
132        '483722993': { cost: 123.6, commission: 0.39, delivery: 105 },
133        '265381213': { cost: 109.2, commission: 0.39, delivery: 105 },
134        '1865968664': { cost: 189.6, commission: 0.39, delivery: 105 },
135        '1361974814': { cost: 127.2, commission: 0.39, delivery: 105 },
136        '1711210766': { cost: 154.8, commission: 0.39, delivery: 105 },
137        '1430070632': { cost: 117.6, commission: 0.39, delivery: 105 },
138        '645347197': { cost: 111.6, commission: 0.39, delivery: 105 },
139        '601547006': { cost: 111.6, commission: 0.39, delivery: 105 },
140        '1554898780': { cost: 159.6, commission: 0.39, delivery: 105 },
141        '576759419': { cost: 146.4, commission: 0.39, delivery: 105 },
142        '361963040': { cost: 145.2, commission: 0.39, delivery: 105 },
143        '1588873517': { cost: 144, commission: 0.39, delivery: 105 },
144        '701743610': { cost: 94.8, commission: 0.39, delivery: 105 },
145        '362561005': { cost: 126, commission: 0.39, delivery: 105 },
146        '1638838932': { cost: 142.8, commission: 0.39, delivery: 105 },
147        '1586310017': { cost: 175.2, commission: 0.39, delivery: 105 },
148        '265381147': { cost: 112.8, commission: 0.39, delivery: 105 },
149        '799722971': { cost: 138, commission: 0.39, delivery: 105 },
150        '701746001': { cost: 133.2, commission: 0.39, delivery: 105 },
151        '885718701': { cost: 129.6, commission: 0.39, delivery: 105 },
152        '627707226': { cost: 135.6, commission: 0.39, delivery: 105 },
153        '907359259': { cost: 157.2, commission: 0.39, delivery: 105 },
154        '1422546406': { cost: 127.2, commission: 0.39, delivery: 105 },
155        '711392959': { cost: 123.6, commission: 0.39, delivery: 105 },
156        '701739222': { cost: 109.2, commission: 0.39, delivery: 105 },
157        '799782895': { cost: 120, commission: 0.39, delivery: 105 },
158        '905741712': { cost: 145.2, commission: 0.39, delivery: 105 },
159        '627696549': { cost: 153.6, commission: 0.39, delivery: 105 },
160        '627691916': { cost: 126, commission: 0.39, delivery: 105 },
161        '1525587675': { cost: 94.8, commission: 0.39, delivery: 105 },
162        '518696433': { cost: 118.8, commission: 0.39, delivery: 105 },
163        '1915145626': { cost: 94.8, commission: 0.39, delivery: 105 },
164        '1915134983': { cost: 92.4, commission: 0.39, delivery: 105 },
165        '1617625622': { cost: 669.6, commission: 0.39, delivery: 105 },
166        '2151674296': { cost: 294, commission: 0.39, delivery: 105 },
167        '1688371971': { cost: 213.6, commission: 0.39, delivery: 105 },
168        '2007269923': { cost: 348, commission: 0.39, delivery: 105 },
169        '1619711279': { cost: 535.2, commission: 0.39, delivery: 105 },
170        '1556227793': { cost: 598.8, commission: 0.39, delivery: 105 },
171        '1556213113': { cost: 624, commission: 0.39, delivery: 105 },
172        '1556033933': { cost: 805.2, commission: 0.39, delivery: 105 },
173        '1614280315': { cost: 711.6, commission: 0.39, delivery: 105 },
174        '1623554699': { cost: 613.2, commission: 0.39, delivery: 105 },
175        '1614312529': { cost: 598.8, commission: 0.39, delivery: 105 },
176        '1556157230': { cost: 568.8, commission: 0.39, delivery: 105 },
177        '1621230498': { cost: 567.6, commission: 0.39, delivery: 105 },
178        '1556203577': { cost: 487.2, commission: 0.39, delivery: 105 },
179        '1619457861': { cost: 476.4, commission: 0.39, delivery: 105 },
180        '1691210828': { cost: 118.8, commission: 0.39, delivery: 105 },
181        '1643979499': { cost: 309.6, commission: 0.39, delivery: 105 },
182        '1467776379': { cost: 175.2, commission: 0.39, delivery: 105 },
183        '881795381': { cost: 204, commission: 0.39, delivery: 105 },
184        '815257353': { cost: 126, commission: 0.39, delivery: 105 },
185        '2196230178': { cost: 96.168, commission: 0.39, delivery: 105 },
186        '2196231035': { cost: 97.332, commission: 0.39, delivery: 105 },
187        '2524038158': { cost: 97.392, commission: 0.39, delivery: 105 },
188        '2196231426': { cost: 97.596, commission: 0.39, delivery: 105 },
189        '2196232023': { cost: 119.916, commission: 0.39, delivery: 105 },
190        '2196243941': { cost: 129.12, commission: 0.39, delivery: 105 },
191        '2196234143': { cost: 134.58, commission: 0.39, delivery: 105 },
192        '320244429': { cost: 158.4, commission: 0.3, delivery: 90 },
193        '240637697': { cost: 108, commission: 0.3, delivery: 90 },
194        '608450235': { cost: 126, commission: 0.3, delivery: 90 },
195        '946421600': { cost: 103.2, commission: 0.3, delivery: 90 },
196        '496076761': { cost: 166.8, commission: 0.3, delivery: 90 },
197        '1413311039': { cost: 135.6, commission: 0.3, delivery: 90 },
198        '440778548': { cost: 708, commission: 0.3, delivery: 90 },
199        '523217298': { cost: 219.6, commission: 0.3, delivery: 90 },
200        '384090220': { cost: 103.2, commission: 0.3, delivery: 90 },
201        '496052718': { cost: 163.2, commission: 0.3, delivery: 90 },
202        '608424787': { cost: 116.4, commission: 0.3, delivery: 90 },
203        '710687654': { cost: 110.4, commission: 0.3, delivery: 90 },
204        '302313862': { cost: 146.4, commission: 0.3, delivery: 90 },
205        '275431854': { cost: 90, commission: 0.3, delivery: 90 },
206        '629089591': { cost: 111.6, commission: 0.3, delivery: 90 },
207        '445990016': { cost: 104.4, commission: 0.3, delivery: 90 },
208        '269055046': { cost: 177.6, commission: 0.3, delivery: 90 },
209        '1006091512': { cost: 100.8, commission: 0.3, delivery: 90 },
210        '541317459': { cost: 163.2, commission: 0.3, delivery: 90 },
211        '643867409': { cost: 170.4, commission: 0.3, delivery: 90 },
212        '1742879159': { cost: 172.8, commission: 0.3, delivery: 90 },
213        '723677583': { cost: 115.2, commission: 0.3, delivery: 90 },
214        '1162597065': { cost: 96, commission: 0.3, delivery: 90 },
215        '240618618': { cost: 117.6, commission: 0.3, delivery: 90 },
216        '308612909': { cost: 286.8, commission: 0.3, delivery: 90 },
217        '641019479': { cost: 90, commission: 0.3, delivery: 90 },
218        '415367670': { cost: 87.6, commission: 0.3, delivery: 90 },
219        '1755740945': { cost: 135.6, commission: 0.3, delivery: 90 },
220        '605720925': { cost: 121.2, commission: 0.3, delivery: 90 },
221        '1787685452': { cost: 124.8, commission: 0.3, delivery: 90 },
222        '930467608': { cost: 312, commission: 0.3, delivery: 90 },
223        '1675833489': { cost: 138, commission: 0.3, delivery: 90 },
224        '523205834': { cost: 120, commission: 0.3, delivery: 90 },
225        '955365874': { cost: 126, commission: 0.3, delivery: 90 },
226        '765946072': { cost: 174, commission: 0.3, delivery: 90 },
227        '302313862': { cost: 146.4, commission: 0.3, delivery: 90 },
228        '275431854': { cost: 90, commission: 0.3, delivery: 90 },
229        '629089591': { cost: 111.6, commission: 0.3, delivery: 90 },
230        '445990016': { cost: 104.4, commission: 0.3, delivery: 90 },
231        '269055046': { cost: 177.6, commission: 0.3, delivery: 90 },
232        '1006091512': { cost: 100.8, commission: 0.3, delivery: 90 },
233        '541317459': { cost: 163.2, commission: 0.3, delivery: 90 },
234        '643867409': { cost: 170.4, commission: 0.3, delivery: 90 },
235        '1742879159': { cost: 172.8, commission: 0.3, delivery: 90 },
236        '723677583': { cost: 115.2, commission: 0.3, delivery: 90 },
237        '1162597065': { cost: 96, commission: 0.3, delivery: 90 },
238        '240618618': { cost: 117.6, commission: 0.3, delivery: 90 },
239        '308612909': { cost: 286.8, commission: 0.3, delivery: 90 },
240        '641019479': { cost: 90, commission: 0.3, delivery: 90 },
241        '415367670': { cost: 87.6, commission: 0.3, delivery: 90 },
242        '1755740945': { cost: 135.6, commission: 0.3, delivery: 90 },
243        '605720925': { cost: 121.2, commission: 0.3, delivery: 90 },
244        '1787685452': { cost: 124.8, commission: 0.3, delivery: 90 },
245        '930467608': { cost: 312, commission: 0.3, delivery: 90 },
246        '1675833489': { cost: 138, commission: 0.3, delivery: 90 },
247        '523205834': { cost: 120, commission: 0.3, delivery: 90 },
248        '955365874': { cost: 126, commission: 0.3, delivery: 90 },
249        '765946072': { cost: 174, commission: 0.3, delivery: 90 },
250        '302474910': { cost: 155.376, commission: 0.3, delivery: 90 },
251        '496313974': { cost: 112.8, commission: 0.3, delivery: 90 },
252        '235921201': { cost: 96, commission: 0.3, delivery: 90 },
253        '257759548': { cost: 129.6, commission: 0.3, delivery: 90 },
254        '1423368794': { cost: 96, commission: 0.3, delivery: 90 },
255        '496162051': { cost: 100.8, commission: 0.3, delivery: 90 },
256        '256464706': { cost: 91.2, commission: 0.3, delivery: 90 },
257        '256403990': { cost: 100.8, commission: 0.3, delivery: 90 },
258        '496078352': { cost: 150, commission: 0.3, delivery: 90 },
259        '439787475': { cost: 128.4, commission: 0.3, delivery: 90 },
260        '2246237790': { cost: 352.8, commission: 0.3, delivery: 90 },
261        '1162432442': { cost: 162, commission: 0.3, delivery: 90 },
262        '496385269': { cost: 117.6, commission: 0.3, delivery: 90 },
263        '235747007': { cost: 123.6, commission: 0.3, delivery: 90 },
264        '240596679': { cost: 82.8, commission: 0.3, delivery: 90 },
265        '946386913': { cost: 67.416, commission: 0.3, delivery: 90 },
266        '1077386569': { cost: 264, commission: 0.3, delivery: 90 },
267        '342033120': { cost: 186, commission: 0.3, delivery: 90 },
268        '327212556': { cost: 88.8, commission: 0.3, delivery: 90 },
269        '257870717': { cost: 133.476, commission: 0.3, delivery: 90 },
270        '523338483': { cost: 165.6, commission: 0.3, delivery: 90 },
271        '955212015': { cost: 175.2, commission: 0.3, delivery: 90 },
272        '2937015180': { cost: 229.2, commission: 0.3, delivery: 90 },
273        '322211321': { cost: 123.6, commission: 0.3, delivery: 90 },
274        '821056923': { cost: 127.2, commission: 0.3, delivery: 90 },
275        '607930809': { cost: 218.4, commission: 0.3, delivery: 90 },
276        '605645338': { cost: 144, commission: 0.3, delivery: 90 },
277        '309603422': { cost: 194.4, commission: 0.3, delivery: 90 },
278        '496192068': { cost: 118.8, commission: 0.3, delivery: 90 },
279        '1225837045': { cost: 192, commission: 0.3, delivery: 90 },
280        '2975092428': { cost: 0, commission: 0.3, delivery: 90 },
281        '2925851542': { cost: 0, commission: 0.3, delivery: 90 },
282        '256499007': { cost: 124.8, commission: 0.3, delivery: 90 },
283        '631642752': { cost: 97.2, commission: 0.3, delivery: 90 },
284        '772649191': { cost: 80.4, commission: 0.3, delivery: 90 },
285        '1609663001': { cost: 217.2, commission: 0.3, delivery: 90 },
286        '530615077': { cost: 108, commission: 0.3, delivery: 90 },
287        '879257026': { cost: 160.8, commission: 0.3, delivery: 90 },
288        '1074695072': { cost: 176.4, commission: 0.3, delivery: 90 },
289        '697745723': { cost: 121.2, commission: 0.3, delivery: 90 },
290        '736971656': { cost: 111.6, commission: 0.3, delivery: 90 },
291        '951571515': { cost: 145.2, commission: 0.3, delivery: 90 },
292        '1773186071': { cost: 220.8, commission: 0.3, delivery: 90 },
293        '203461072': { cost: 204, commission: 0.3, delivery: 90 },
294        '496104827': { cost: 114, commission: 0.3, delivery: 90 },
295        '292190882': { cost: 102, commission: 0.3, delivery: 90 },
296        '1653722295': { cost: 218.4, commission: 0.3, delivery: 90 },
297        '1122871855': { cost: 216, commission: 0.3, delivery: 90 },
298        '1931646505': { cost: 136.8, commission: 0.3, delivery: 90 },
299        '439682438': { cost: 69.6, commission: 0.3, delivery: 90 },
300        '496210001': { cost: 72, commission: 0.3, delivery: 90 },
301        '1620775285': { cost: 112.8, commission: 0.3, delivery: 90 },
302        '1617839244': { cost: 114, commission: 0.3, delivery: 90 },
303        '1787676082': { cost: 243.6, commission: 0.3, delivery: 90 },
304        '631658690': { cost: 91.2, commission: 0.3, delivery: 90 },
305        '257885915': { cost: 133.488, commission: 0.3, delivery: 90 },
306        '1805680376': { cost: 58.8, commission: 0.3, delivery: 90 },
307        '540355209': { cost: 159.6, commission: 0.3, delivery: 90 },
308        '1742877411': { cost: 208.8, commission: 0.3, delivery: 90 },
309        '1418275068': { cost: 158.4, commission: 0.3, delivery: 90 },
310        '2899612149': { cost: 145.2, commission: 0.3, delivery: 90 },
311        '2963203543': { cost: 129.948, commission: 0.3, delivery: 90 },
312        '607968165': { cost: 103.2, commission: 0.3, delivery: 90 },
313        '1162462310': { cost: 180, commission: 0.3, delivery: 90 },
314        '1507555262': { cost: 114, commission: 0.3, delivery: 90 },
315        '2925821091': { cost: 0, commission: 0.3, delivery: 90 },
316        '608298877': { cost: 136.8, commission: 0.3, delivery: 90 },
317        '1239708831': { cost: 169.2, commission: 0.3, delivery: 90 },
318        '1724749801': { cost: 180, commission: 0.3, delivery: 90 },
319        '439673824': { cost: 140.4, commission: 0.3, delivery: 90 },
320        '496542249': { cost: 81.6, commission: 0.3, delivery: 90 },
321        '1417508954': { cost: 122.4, commission: 0.3, delivery: 90 },
322        '372062053': { cost: 140.4, commission: 0.3, delivery: 90 },
323        '235824492': { cost: 105.6, commission: 0.3, delivery: 90 },
324        '912117351': { cost: 153.6, commission: 0.3, delivery: 90 },
325        '1162577837': { cost: 117.6, commission: 0.3, delivery: 90 },
326        '838273559': { cost: 163.2, commission: 0.3, delivery: 90 },
327        '953470782': { cost: 134.4, commission: 0.3, delivery: 90 },
328        '1591125774': { cost: 328.8, commission: 0.3, delivery: 90 },
329        '1239742307': { cost: 139.2, commission: 0.3, delivery: 90 },
330        '422559168': { cost: 159.6, commission: 0.3, delivery: 90 },
331        '1581558117': { cost: 117.6, commission: 0.3, delivery: 90 },
332        '697870104': { cost: 92.4, commission: 0.3, delivery: 90 },
333        '561033759': { cost: 112.8, commission: 0.3, delivery: 90 },
334        '1696256652': { cost: 115.2, commission: 0.3, delivery: 90 },
335        '2925806092': { cost: 0, commission: 0.3, delivery: 90 },
336        '1911238277': { cost: 103.2, commission: 0.3, delivery: 90 },
337        '282398558': { cost: 123.6, commission: 0.3, delivery: 90 },
338        '1880336894': { cost: 340.8, commission: 0.3, delivery: 90 },
339        '1394598690': { cost: 127.2, commission: 0.3, delivery: 90 },
340        '1161957584': { cost: 141.6, commission: 0.3, delivery: 90 },
341        '697830627': { cost: 182.4, commission: 0.3, delivery: 90 },
342        '307964008': { cost: 94.8, commission: 0.3, delivery: 90 },
343        '254895676': { cost: 112.8, commission: 0.3, delivery: 90 },
344        '1417478667': { cost: 124.8, commission: 0.3, delivery: 90 },
345        '1609652145': { cost: 144, commission: 0.3, delivery: 90 },
346        '1010086939': { cost: 141.6, commission: 0.3, delivery: 90 },
347        '952853707': { cost: 128.4, commission: 0.3, delivery: 90 },
348        '1665302366': { cost: 224.4, commission: 0.3, delivery: 90 },
349        '302361373': { cost: 104.4, commission: 0.3, delivery: 90 },
350        '952754284': { cost: 144.54, commission: 0.3, delivery: 90 },
351        '273926369': { cost: 88.8, commission: 0.3, delivery: 90 },
352        '838115048': { cost: 164.4, commission: 0.3, delivery: 90 },
353        '838251281': { cost: 103.788, commission: 0.3, delivery: 90 },
354        '732238010': { cost: 148.8, commission: 0.3, delivery: 90 },
355        '445989855': { cost: 85.2, commission: 0.3, delivery: 90 },
356        '269076077': { cost: 301.452, commission: 0.3, delivery: 90 },
357        '257568474': { cost: 73.2, commission: 0.3, delivery: 90 },
358        '954664346': { cost: 129.6, commission: 0.3, delivery: 90 },
359        '254600991': { cost: 132, commission: 0.3, delivery: 90 },
360        '772640606': { cost: 106.8, commission: 0.3, delivery: 90 },
361        '955283837': { cost: 182.4, commission: 0.3, delivery: 90 },
362        '254686077': { cost: 174, commission: 0.3, delivery: 90 },
363        '1394711785': { cost: 144, commission: 0.3, delivery: 90 },
364        '257884238': { cost: 130.8, commission: 0.3, delivery: 90 },
365        '1620776878': { cost: 157.2, commission: 0.3, delivery: 90 },
366        '951783485': { cost: 132, commission: 0.3, delivery: 90 },
367        '356177679': { cost: 69.6, commission: 0.3, delivery: 90 },
368        '1394612090': { cost: 159.6, commission: 0.3, delivery: 90 },
369        '2897675749': { cost: 0, commission: 0.3, delivery: 90 },
370        '1162445078': { cost: 186, commission: 0.3, delivery: 90 },
371        '1932949948': { cost: 235.2, commission: 0.3, delivery: 90 },
372        '879083250': { cost: 186, commission: 0.3, delivery: 90 },
373        '256466996': { cost: 200.4, commission: 0.3, delivery: 90 },
374        '3006918397': { cost: 313.2, commission: 0.3, delivery: 90 },
375        '1418277399': { cost: 346.8, commission: 0.3, delivery: 90 },
376        '496419419': { cost: 258, commission: 0.3, delivery: 90 },
377        '1007822873': { cost: 134.4, commission: 0.3, delivery: 90 },
378        '608351238': { cost: 120, commission: 0.3, delivery: 90 },
379        '1413857256': { cost: 159.6, commission: 0.3, delivery: 90 },
380        '1787673702': { cost: 150, commission: 0.3, delivery: 90 },
381        '1162216260': { cost: 145.2, commission: 0.3, delivery: 90 },
382        '1413837107': { cost: 87.6, commission: 0.3, delivery: 90 },
383        '768941637': { cost: 171.6, commission: 0.3, delivery: 90 },
384        '1507653510': { cost: 96, commission: 0.3, delivery: 90 },
385        '1007787669': { cost: 132, commission: 0.3, delivery: 90 },
386        '2352209417': { cost: 283.752, commission: 0.3, delivery: 90 },
387        '1397098991': { cost: 331.2, commission: 0.3, delivery: 90 },
388        '1507630430': { cost: 99.6, commission: 0.3, delivery: 90 },
389        '1189589105': { cost: 130.8, commission: 0.3, delivery: 90 },
390        '1506037461': { cost: 470.4, commission: 0.3, delivery: 90 },
391        '1162348932': { cost: 194.4, commission: 0.3, delivery: 90 },
392        '2975103256': { cost: 163.056, commission: 0.3, delivery: 90 },
393        '1506047716': { cost: 171.6, commission: 0.3, delivery: 90 },
394        '911292485': { cost: 112.8, commission: 0.3, delivery: 90 },
395        '1880333546': { cost: 364.8, commission: 0.3, delivery: 90 },
396        '1608793966': { cost: 132, commission: 0.3, delivery: 90 },
397        '1880315436': { cost: 344.4, commission: 0.3, delivery: 90 },
398        '2352282340': { cost: 283.752, commission: 0.3, delivery: 90 },
399        '709600226': { cost: 129.6, commission: 0.3, delivery: 90 },
400        '3016287234': { cost: 274.8, commission: 0.3, delivery: 90 },
401        '3016266763': { cost: 240, commission: 0.3, delivery: 90 },
402        '3026343193': { cost: 283.2, commission: 0.3, delivery: 90 },
403        '3011261105': { cost: 208.8, commission: 0.3, delivery: 90 },
404        '3026384906': { cost: 309.6, commission: 0.3, delivery: 90 },
405        '1303951724': { cost: 67.2, commission: 0.3, delivery: 90 },
406        '3026360459': { cost: 310.8, commission: 0.3, delivery: 90 },
407        '951614842': { cost: 116.4, commission: 0.3, delivery: 90 },
408        '1758263220': { cost: 776.4, commission: 0.3, delivery: 90 },
409        '1162674702': { cost: 152.4, commission: 0.3, delivery: 90 },
410        '236327983': { cost: 120, commission: 0.3, delivery: 90 },
411        '256416463': { cost: 104.4, commission: 0.3, delivery: 90 },
412        '1790465865': { cost: 62.4, commission: 0.3, delivery: 90 },
413        '2975215156': { cost: 163.056, commission: 0.3, delivery: 90 },
414        '1005952104': { cost: 94.8, commission: 0.3, delivery: 90 },
415        '399215466': { cost: 102, commission: 0.3, delivery: 90 },
416        '1162300125': { cost: 116.4, commission: 0.3, delivery: 90 },
417        '1005952110': { cost: 93.6, commission: 0.3, delivery: 90 },
418        '496044796': { cost: 116.4, commission: 0.3, delivery: 90 },
419        '203389028': { cost: 166.8, commission: 0.3, delivery: 90 },
420        '1005550551': { cost: 96, commission: 0.3, delivery: 90 },
421        '203480472': { cost: 94.8, commission: 0.3, delivery: 90 },
422        '203473290': { cost: 121.2, commission: 0.3, delivery: 90 },
423        '1620772534': { cost: 321.6, commission: 0.3, delivery: 90 },
424        '282469378': { cost: 100.8, commission: 0.3, delivery: 90 },
425        '1805671797': { cost: 58.8, commission: 0.3, delivery: 90 },
426        '203350791': { cost: 134.4, commission: 0.3, delivery: 90 },
427        '1394625221': { cost: 129.6, commission: 0.3, delivery: 90 },
428        '301908659': { cost: 111.6, commission: 0.3, delivery: 90 },
429        '1507673120': { cost: 253.2, commission: 0.36, delivery: 200 },
430        '1239609957': { cost: 123.6, commission: 0.36, delivery: 200 },
431        '1006163518': { cost: 188.4, commission: 0.36, delivery: 200 },
432        '1422925703': { cost: 252, commission: 0.36, delivery: 200 },
433        '1572975136': { cost: 547.2, commission: 0.36, delivery: 200 },
434        '2394561998': { cost: 106.8, commission: 0.36, delivery: 200 },
435        '838220448': { cost: 136.8, commission: 0.36, delivery: 200 },
436        '543848911': { cost: 228, commission: 0.36, delivery: 200 },
437        '1020579419': { cost: 88.8, commission: 0.36, delivery: 200 },
438        '557726786': { cost: 217.2, commission: 0.36, delivery: 200 },
439        '1608785751': { cost: 176.4, commission: 0.36, delivery: 200 },
440        '1020578939': { cost: 92.4, commission: 0.36, delivery: 200 },
441        '519816761': { cost: 231.6, commission: 0.36, delivery: 200 },
442        '1673659402': { cost: 1267, commission: 0.36, delivery: 200 },
443        '501441185': { cost: 216, commission: 0.36, delivery: 200 },
444        '860254877': { cost: 223.2, commission: 0.36, delivery: 200 },
445        '774068400': { cost: 358.8, commission: 0.36, delivery: 200 },
446        '519740742': { cost: 216, commission: 0.36, delivery: 200 },
447        '1673650914': { cost: 1537, commission: 0.36, delivery: 200 },
448        '519734762': { cost: 234, commission: 0.36, delivery: 200 },
449        '1558177759': { cost: 366, commission: 0.36, delivery: 200 },
450        '1558176776': { cost: 421.2, commission: 0.36, delivery: 200 },
451        '643844171': { cost: 112.8, commission: 0.36, delivery: 200 },
452        '519732586': { cost: 98.4, commission: 0.36, delivery: 200 },
453        '1019659629': { cost: 91.2, commission: 0.36, delivery: 200 },
454        '1673649384': { cost: 1517, commission: 0.36, delivery: 200 },
455        '860261495': { cost: 240, commission: 0.36, delivery: 200 },
456        '1880450237': { cost: 271.2, commission: 0.36, delivery: 200 },
457        '1558174139': { cost: 372, commission: 0.36, delivery: 200 },
458        '1845802065': { cost: 768, commission: 0.36, delivery: 200 },
459        '1673647587': { cost: 1497, commission: 0.36, delivery: 200 },
460        '557670932': { cost: 392.4, commission: 0.36, delivery: 200 },
461        '1979738121': { cost: 637.2, commission: 0.36, delivery: 200 },
462        '1020579926': { cost: 88.8, commission: 0.36, delivery: 200 },
463        '1880440770': { cost: 273.6, commission: 0.36, delivery: 200 },
464        '1979755177': { cost: 662.4, commission: 0.36, delivery: 200 },
465        '2898154255': { cost: 124.8, commission: 0.36, delivery: 200 },
466        '2899553513': { cost: 145.2, commission: 0.36, delivery: 200 },
467        '1846354292': { cost: 768, commission: 0.36, delivery: 200 },
468        '1880410608': { cost: 285.6, commission: 0.36, delivery: 200 },
469        '2898115411': { cost: 136.8, commission: 0.36, delivery: 200 },
470        '1880442651': { cost: 270, commission: 0.36, delivery: 200 },
471        '501438861': { cost: 220.8, commission: 0.36, delivery: 200 },
472        '1397099331': { cost: 372, commission: 0.36, delivery: 200 },
473        '1846363096': { cost: 768, commission: 0.36, delivery: 200 },
474        '2631471568': { cost: 685.2, commission: 0.36, delivery: 200 },
475        '1911710527': { cost: 276, commission: 0.36, delivery: 200 },
476        '1911695310': { cost: 267.6, commission: 0.36, delivery: 200 },
477        '1911704413': { cost: 264, commission: 0.36, delivery: 200 },
478        '1020579746': { cost: 90, commission: 0.36, delivery: 200 },
479        '335431876': { cost: 51.6, commission: 0.36, delivery: 200 },
480        '439685200': { cost: 55.2, commission: 0.36, delivery: 200 },
481        '1019698970': { cost: 88.8, commission: 0.36, delivery: 200 },
482        '439692165': { cost: 55.2, commission: 0.36, delivery: 200 },
483        '335431975': { cost: 54, commission: 0.36, delivery: 200 },
484        '335446268': { cost: 52.8, commission: 0.36, delivery: 200 },
485        '1846315219': { cost: 768, commission: 0.36, delivery: 200 },
486        '335440088': { cost: 61.2, commission: 0.36, delivery: 200 },
487        '838167533': { cost: 106.8, commission: 0.3, delivery: 90 },
488        '878312141': { cost: 265.2, commission: 0.36, delivery: 200 },
489        '1572991087': { cost: 290.4, commission: 0.36, delivery: 200 },
490        '1521855158': { cost: 104.4, commission: 0.3, delivery: 90 },
491        '646434083': { cost: 252, commission: 0.3, delivery: 90 },
492        '646441179': { cost: 273.6, commission: 0.3, delivery: 90 },
493        '2352128160': { cost: 340.8, commission: 0.36, delivery: 200 },
494        '446010027': { cost: 344.4, commission: 0.3, delivery: 90 },
495        '1773177807': { cost: 192, commission: 0.36, delivery: 200 },
496        '1980328072': { cost: 338.4, commission: 0.36, delivery: 200 },
497        '646441673': { cost: 258, commission: 0.3, delivery: 90 },
498        '772524320': { cost: 131.64, commission: 0.3, delivery: 90 },
499        '302573933': { cost: 258, commission: 0.3, delivery: 90 },
500        '824213857': { cost: 172.8, commission: 0.3, delivery: 90 },
501        '1609643510': { cost: 175.2, commission: 0.3, delivery: 90 },
502        '439749049': { cost: 357.6, commission: 0.3, delivery: 90 },
503        '496064096': { cost: 230.052, commission: 0.3, delivery: 90 },
504        '732341657': { cost: 205.2, commission: 0.36, delivery: 200 },
505        '955327749': { cost: 146.4, commission: 0.3, delivery: 90 },
506        '1787680920': { cost: 230.4, commission: 0.3, delivery: 90 },
507        '2352063264': { cost: 285.6, commission: 0.36, delivery: 200 },
508        '2352107373': { cost: 321.6, commission: 0.36, delivery: 200 },
509        '1521854115': { cost: 177.6, commission: 0.3, delivery: 90 },
510        '240602548': { cost: 128.4, commission: 0.3, delivery: 90 },
511        '1239644265': { cost: 207.6, commission: 0.3, delivery: 90 },
512        '203465007': { cost: 124.8, commission: 0.36, delivery: 200 },
513        '1937534346': { cost: 144, commission: 0.3, delivery: 90 },
514        '1979698296': { cost: 324, commission: 0.36, delivery: 200 },
515        '256430704': { cost: 99.6, commission: 0.3, delivery: 90 },
516        '1505980019': { cost: 183.6, commission: 0.3, delivery: 90 }
517    };
518
519    // Extract product ID from URL
520    function getProductId() {
521        const match = window.location.href.match(/product\/[^\/]+-(\d+)/);
522        return match ? match[1] : null;
523    }
524
525    // Get short SKU from full product ID (last 5 digits)
526    function getShortSku(fullProductId) {
527        if (PRODUCT_DATA[fullProductId]) {
528            return fullProductId;
529        }
530        
531        const last5 = fullProductId.slice(-5);
532        if (PRODUCT_DATA[last5]) {
533            return last5;
534        }
535        
536        const last6 = fullProductId.slice(-6);
537        if (PRODUCT_DATA[last6]) {
538            return last6;
539        }
540        
541        return null;
542    }
543
544    // Extract daily price and sales data from MP Stats chart
545    async function extractDailyDataFromChart(widget) {
546        console.log('>>> extractDailyDataFromChart CALLED (ECharts version) <<<');
547        
548        try {
549            const dailyData = [];
550            
551            // Find ECharts canvas elements
552            const canvases = widget.querySelectorAll('canvas[data-zr-dom-id]');
553            console.log('Found ECharts canvas elements:', canvases.length);
554            
555            if (canvases.length === 0) {
556                console.log('No canvas charts found');
557                return dailyData;
558            }
559            
560            const salesCanvas = canvases[0];
561            console.log('Analyzing sales chart (Canvas 0)...');
562            
563            const rect = salesCanvas.getBoundingClientRect();
564            console.log('Canvas rect:', rect);
565            
566            const seenDates = new Set();
567            
568            // Try 30 points (30 days) with multiple Y positions
569            for (let day = 0; day < 30; day++) {
570                let found = false;
571                
572                // Try different Y positions (top to bottom) to hit the bars
573                for (let yOffset = 0.2; yOffset <= 0.8 && !found; yOffset += 0.15) {
574                    const xPos = rect.left + (rect.width * ((day + 0.5) / 30));
575                    const yPos = rect.top + rect.height * yOffset;
576                    
577                    salesCanvas.dispatchEvent(new MouseEvent('mousemove', {
578                        bubbles: true,
579                        cancelable: true,
580                        view: window,
581                        clientX: xPos,
582                        clientY: yPos
583                    }));
584                    
585                    await new Promise(resolve => setTimeout(resolve, 150));
586                    
587                    // Find tooltip with sales and price data
588                    const allElements = Array.from(document.querySelectorAll('*'));
589                    const tooltip = allElements.find(el => {
590                        const text = el.textContent;
591                        return text.includes('Продажи:') && text.includes('Цена:') && 
592                               window.getComputedStyle(el).position === 'absolute';
593                    });
594                    
595                    if (tooltip) {
596                        const text = tooltip.textContent;
597                        const salesMatch = text.match(/Продажи:\s*(\d+)\s*шт/);
598                        const priceMatch = text.match(/Цена:\s*(\d+)\s*₽/);
599                        const dateMatch = text.match(/(\d+)\s+(января|февраля|марта|апреля|мая|июня|июля|августа|сентября|октября|ноября|декабря)\s+(\d+)/);
600                        
601                        if (salesMatch && priceMatch && dateMatch) {
602                            const dateKey = dateMatch[0];
603                            if (!seenDates.has(dateKey)) {
604                                seenDates.add(dateKey);
605                                const sales = parseInt(salesMatch[1]);
606                                const price = parseInt(priceMatch[1]);
607                                
608                                dailyData.push({
609                                    day: dailyData.length + 1,
610                                    date: dateKey,
611                                    sales: sales,
612                                    price: price
613                                });
614                                
615                                console.log(`Day ${dailyData.length}: ${dateKey} - ${sales} шт @ ${price}`);
616                                found = true;
617                            }
618                        }
619                    }
620                }
621            }
622            
623            console.log(`Total extracted daily data points: ${dailyData.length}`);
624            console.log('Sample data - First 5 days:', dailyData.slice(0, 5));
625            console.log('Sample data - Last 5 days:', dailyData.slice(-5));
626            return dailyData;
627            
628        } catch (error) {
629            console.error('Error extracting daily data:', error);
630            return [];
631        }
632    }
633
634    // Extract stock data from MP Stats stock chart
635    async function extractStockData(widget) {
636        console.log('Extracting stock data from MP Stats (ECharts version)...');
637        
638        if (!widget) {
639            console.error('Widget not provided to extractStockData');
640            return null;
641        }
642        
643        // Find ECharts canvas elements
644        const canvases = widget.querySelectorAll('canvas[data-zr-dom-id]');
645        console.log(`Found ${canvases.length} canvas charts for stock data`);
646        
647        if (!canvases || canvases.length < 4) {
648            console.error(`Stock chart canvas not found - only ${canvases ? canvases.length : 0} charts available, need at least 4`);
649            return null;
650        }
651        
652        const stockCanvas = canvases[3];
653        console.log('Analyzing stock chart (Canvas 3)...');
654        
655        const rect = stockCanvas.getBoundingClientRect();
656        console.log('Stock canvas rect:', rect);
657
658        const stockPoints = [];
659        const seenDates = new Set();
660        console.log('Starting stock tooltip extraction...');
661        
662        // Try 30 points (30 days) with multiple Y positions
663        for (let day = 0; day < 30; day++) {
664            let found = false;
665            
666            // Try different Y positions (top to bottom) to hit the bars
667            for (let yOffset = 0.2; yOffset <= 0.8 && !found; yOffset += 0.15) {
668                const xPos = rect.left + (rect.width * ((day + 0.5) / 30));
669                const yPos = rect.top + rect.height * yOffset;
670                
671                stockCanvas.dispatchEvent(new MouseEvent('mousemove', {
672                    bubbles: true,
673                    cancelable: true,
674                    view: window,
675                    clientX: xPos,
676                    clientY: yPos
677                }));
678                
679                await new Promise(resolve => setTimeout(resolve, 150));
680                
681                // Find tooltip with stock data
682                const allElements = Array.from(document.querySelectorAll('*'));
683                const tooltip = allElements.find(el => {
684                    const text = el.textContent;
685                    return text.includes('Остаток:') && text.includes('шт') && 
686                           window.getComputedStyle(el).position === 'absolute';
687                });
688                
689                if (tooltip) {
690                    const text = tooltip.textContent;
691                    const stockMatch = text.match(/Остаток:\s*(\d+)\s*шт/);
692                    const dateMatch = text.match(/(\d+)\s+(января|февраля|марта|апреля|мая|июня|июля|августа|сентября|октября|ноября|декабря)\s+(\d+)/);
693                    
694                    if (stockMatch && dateMatch) {
695                        const dateKey = dateMatch[0];
696                        if (!seenDates.has(dateKey)) {
697                            seenDates.add(dateKey);
698                            const stock = parseInt(stockMatch[1]);
699                            
700                            stockPoints.push({
701                                day: stockPoints.length + 1,
702                                date: dateKey,
703                                stock: stock
704                            });
705                            
706                            console.log(`Stock Day ${stockPoints.length}: ${dateKey} - ${stock} шт`);
707                            found = true;
708                        }
709                    }
710                }
711            }
712        }
713
714        console.log(`Extracted ${stockPoints.length} days of stock data from chart`);
715        console.log('Stock data sample - First 5 days:', stockPoints.slice(0, 5));
716        console.log('Stock data sample - Last 5 days:', stockPoints.slice(-5));
717        return stockPoints;
718    }
719
720    // NEW: Filter outliers using IQR method
721    function filterOutliers(dataPoints) {
722        console.log('=== FILTERING OUTLIERS (IQR Method) ===');
723        console.log('Original data points:', dataPoints.length);
724        
725        if (!dataPoints || dataPoints.length < 5) {
726            console.log('Not enough data for outlier filtering');
727            return dataPoints;
728        }
729        
730        // Step 1: Remove zero sales
731        let filtered = dataPoints.filter(d => d.sales > 0);
732        console.log(`After removing zero sales: ${filtered.length} points (removed ${dataPoints.length - filtered.length})`);
733        
734        if (filtered.length < 5) {
735            console.log('Not enough data after removing zero sales');
736            return filtered;
737        }
738        
739        // Step 2: IQR filtering for prices
740        const prices = filtered.map(d => d.price).sort((a, b) => a - b);
741        const priceQ1 = prices[Math.floor(prices.length * 0.25)];
742        const priceQ3 = prices[Math.floor(prices.length * 0.75)];
743        const priceIQR = priceQ3 - priceQ1;
744        const priceLowerBound = priceQ1 - 1.5 * priceIQR;
745        const priceUpperBound = priceQ3 + 1.5 * priceIQR;
746        
747        console.log(`Price IQR: Q1=${priceQ1}, Q3=${priceQ3}, IQR=${priceIQR}`);
748        console.log(`Price bounds: [${priceLowerBound}, ${priceUpperBound}]`);
749        
750        filtered = filtered.filter(d => d.price >= priceLowerBound && d.price <= priceUpperBound);
751        console.log(`After price outlier removal: ${filtered.length} points`);
752        
753        if (filtered.length < 5) {
754            console.log('Not enough data after price filtering');
755            return filtered;
756        }
757        
758        // Step 3: IQR filtering for sales
759        const sales = filtered.map(d => d.sales).sort((a, b) => a - b);
760        const salesQ1 = sales[Math.floor(sales.length * 0.25)];
761        const salesQ3 = sales[Math.floor(sales.length * 0.75)];
762        const salesIQR = salesQ3 - salesQ1;
763        const salesLowerBound = salesQ1 - 1.5 * salesIQR;
764        const salesUpperBound = salesQ3 + 1.5 * salesIQR;
765        
766        console.log(`Sales IQR: Q1=${salesQ1}, Q3=${salesQ3}, IQR=${salesIQR}`);
767        console.log(`Sales bounds: [${salesLowerBound}, ${salesUpperBound}]`);
768        
769        const beforeSalesFilter = filtered.length;
770        filtered = filtered.filter(d => d.sales >= salesLowerBound && d.sales <= salesUpperBound);
771        console.log(`After sales outlier removal: ${filtered.length} points (removed ${beforeSalesFilter - filtered.length})`);
772        
773        console.log(`=== OUTLIER FILTERING COMPLETE: ${dataPoints.length}${filtered.length} points ===`);
774        return filtered;
775    }
776
777    // NEW: Determine product segment based on competitive positioning
778    function determineProductSegment(currentPrice, competitorPrices) {
779        console.log('=== DETERMINING PRODUCT SEGMENT ===');
780        
781        if (!competitorPrices || competitorPrices.length === 0) {
782            console.log('No competitor data, defaulting to mid-market segment');
783            return {
784                segment: 'mid-market',
785                description: 'Средний сегмент (нет данных о конкурентах)',
786                strategy: 'Оптимизация прибыли с учетом эластичности спроса'
787            };
788        }
789        
790        const prices = competitorPrices.map(c => c.price).sort((a, b) => a - b);
791        const minPrice = Math.min(...prices);
792        const maxPrice = Math.max(...prices);
793        const avgPrice = prices.reduce((a, b) => a + b, 0) / prices.length;
794        const medianPrice = prices[Math.floor(prices.length / 2)];
795        
796        console.log(`Price analysis: min=${minPrice}, max=${maxPrice}, avg=${avgPrice.toFixed(0)}, median=${medianPrice}`);
797        console.log(`Current price: ${currentPrice}`);
798        
799        const pricePosition = (currentPrice - minPrice) / (maxPrice - minPrice);
800        console.log(`Price position: ${(pricePosition * 100).toFixed(1)}% of range`);
801        
802        let segment, description, strategy;
803        
804        if (currentPrice < avgPrice * 0.8) {
805            segment = 'budget';
806            description = 'Бюджетный сегмент (цена ниже рынка на 20%+)';
807            strategy = 'Захват доли рынка через низкую цену. Фокус на объёме продаж.';
808        } else if (currentPrice < avgPrice * 0.95) {
809            segment = 'value';
810            description = 'Ценностный сегмент (цена немного ниже среднего)';
811            strategy = 'Баланс цены и качества. Конкурентное преимущество по цене.';
812        } else if (currentPrice <= avgPrice * 1.05) {
813            segment = 'mid-market';
814            description = 'Средний сегмент (цена на уровне рынка)';
815            strategy = 'Оптимизация прибыли. Конкуренция по качеству и сервису.';
816        } else if (currentPrice <= avgPrice * 1.2) {
817            segment = 'premium';
818            description = 'Премиум сегмент (цена выше среднего на 5-20%)';
819            strategy = 'Позиционирование как премиум продукт. Фокус на маржинальности.';
820        } else {
821            segment = 'luxury';
822            description = 'Люкс сегмент (цена выше рынка на 20%+)';
823            strategy = 'Эксклюзивное позиционирование. Максимальная маржа, низкий объём.';
824        }
825        
826        console.log(`Segment: ${segment} - ${description}`);
827        console.log(`Strategy: ${strategy}`);
828        
829        return { segment, description, strategy };
830    }
831
832    // NEW: Calculate inventory strategy based on days of supply
833    function getInventoryStrategy(daysOfSupply) {
834        console.log('=== CALCULATING INVENTORY STRATEGY ===');
835        console.log(`Days of supply: ${daysOfSupply.toFixed(1)}`);
836        
837        let strategy, action, priceAdjustment;
838        
839        if (daysOfSupply < 7) {
840            strategy = 'critical_low';
841            action = 'Критически низкий остаток';
842            priceAdjustment = 'НЕ СНИЖАТЬ цену. Можно повысить на 5-10% для максимизации прибыли.';
843        } else if (daysOfSupply <= 30) {
844            strategy = 'low';
845            action = 'Низкий остаток';
846            priceAdjustment = 'Оптимизация прибыли. Небольшое повышение цены допустимо.';
847        } else if (daysOfSupply <= 90) {
848            strategy = 'optimal';
849            action = 'Оптимальный остаток';
850            priceAdjustment = 'Стандартная оптимизация прибыли по эластичности спроса.';
851        } else if (daysOfSupply <= 180) {
852            strategy = 'high';
853            action = 'Высокий остаток';
854            priceAdjustment = 'Можно снижать цену для ускорения продаж и освобождения склада.';
855        } else {
856            strategy = 'critical_high';
857            action = 'Критически высокий остаток';
858            priceAdjustment = 'АГРЕССИВНОЕ снижение цены! Риск затоваривания и списания.';
859        }
860        
861        console.log(`Strategy: ${strategy} - ${action}`);
862        console.log(`Price adjustment: ${priceAdjustment}`);
863        
864        return { strategy, action, priceAdjustment, daysOfSupply };
865    }
866
867    // NEW: Extract competitors from search query
868    async function extractCompetitorsFromSearch(keyQuery) {
869        console.log('=== START extractCompetitorsFromSearch ===');
870        console.log('Key query:', keyQuery);
871        
872        try {
873            // Encode query for URL
874            const encodedQuery = encodeURIComponent(keyQuery);
875            const searchUrl = `https://www.ozon.ru/search/?text=${encodedQuery}&from_global=true`;
876            
877            console.log('Opening search URL in new tab:', searchUrl);
878            console.log('⚠️ ВАЖНО: Новая вкладка откроется для сбора данных о конкурентах. Пожалуйста, не закрывайте её - она закроется автоматически.');
879            
880            // Open search page in new tab (in foreground so user can see it)
881            await GM.openInTab(searchUrl, true);
882            
883            // Wait for new tab to load and process
884            console.log('Waiting for search page to load...');
885            
886            // The new tab will handle extraction and save to storage
887            // This function just initiates the process
888            return null;
889            
890        } catch (error) {
891            console.error('Error in extractCompetitorsFromSearch:', error);
892            return null;
893        }
894    }
895
896    // NEW: Extract competitors in search page context
897    async function extractCompetitorsInSearchPage() {
898        console.log('=== extractCompetitorsInSearchPage CALLED ===');
899        
900        // Check if we're on a search or category page
901        if (!window.location.href.includes('/search/') && !window.location.href.includes('/category/')) {
902            console.log('Not on search/category page, skipping competitor extraction');
903            return;
904        }
905        
906        // Check if we have a pending analysis state (meaning we came from product page)
907        const stateJson = await GM.getValue('analysis_state', null);
908        if (!stateJson) {
909            console.log('No analysis state found, not extracting competitors');
910            return;
911        }
912        
913        const state = JSON.parse(stateJson);
914        
915        // Check if state is recent (within 2 minutes)
916        if (Date.now() - state.timestamp > 120000) {
917            console.log('Analysis state is too old, ignoring');
918            await GM.deleteValue('analysis_state');
919            return;
920        }
921        
922        console.log('Found analysis state, will extract competitors from this search page');
923        console.log('Our product ID:', state.productId);
924        
925        // Wait for MPStats widget to load
926        console.log('Waiting for MPStats widget to load...');
927        let mpstatsWidget = null;
928        let attempts = 0;
929        const maxAttempts = 30;
930        
931        while (attempts < maxAttempts && !mpstatsWidget) {
932            await new Promise(resolve => setTimeout(resolve, 1000));
933            mpstatsWidget = document.getElementById('mpstat-ozone-search-result');
934            attempts++;
935            console.log(`Attempt ${attempts}/${maxAttempts} to find MPStats widget...`);
936        }
937        
938        if (!mpstatsWidget) {
939            console.error('MPStats widget not found in search results after 30 seconds');
940            // Mark as failed and close tab
941            await GM.setValue('competitors_extracted', 'failed');
942            window.close();
943            return;
944        }
945        
946        console.log('MPStats widget found, waiting for data to load...');
947        
948        // Wait for table rows to appear
949        let rows = [];
950        attempts = 0;
951        
952        while (attempts < 20 && rows.length === 0) {
953            await new Promise(resolve => setTimeout(resolve, 1000));
954            rows = mpstatsWidget.querySelectorAll('tbody tr');
955            attempts++;
956            console.log(`Attempt ${attempts}/20: Found ${rows.length} rows`);
957        }
958        
959        if (rows.length === 0) {
960            console.error('No rows found in MPStats table after waiting');
961            await GM.setValue('competitors_extracted', 'failed');
962            window.close();
963            return;
964        }
965        
966        console.log(`Found ${rows.length} rows in MPStats table, extracting competitor data...`);
967        
968        const competitors = [];
969        
970        for (let i = 0; i < rows.length; i++) {
971            const row = rows[i];
972            
973            try {
974                // Extract SKU from the third column
975                const skuCell = row.querySelectorAll('td')[2];
976                if (!skuCell) continue;
977                
978                const skuText = skuCell.textContent.trim();
979                const sku = skuText.match(/\d+/) ? skuText.match(/\d+/)[0] : null;
980                
981                if (!sku) continue;
982                
983                // ⚠️ NEW: Skip our own product
984                if (sku === state.productId || sku === state.shortSku) {
985                    console.log(`⚠️ Skipping our own product: SKU ${sku}`);
986                    continue;
987                }
988                
989                // Extract brand from the fourth column
990                const brandCell = row.querySelectorAll('td')[3];
991                if (!brandCell) continue;
992                
993                const brand = brandCell.textContent.trim();
994                
995                if (!brand || brand.length < 2) continue;
996                
997                // Extract price from the fifth column
998                const priceCell = row.querySelectorAll('td')[4];
999                if (!priceCell) continue;
1000                
1001                const priceText = priceCell.textContent.trim();
1002                const priceMatch = priceText.match(/(\d[\d\s]*)\s*₽/);
1003                if (!priceMatch) continue;
1004                
1005                const price = parseInt(priceMatch[1].replace(/\s/g, ''));
1006                if (isNaN(price) || price < 100 || price > 100000) continue;
1007                
1008                // Extract sales from the sixth column (orders per month)
1009                const salesCell = row.querySelectorAll('td')[5];
1010                if (!salesCell) continue;
1011                
1012                const salesText = salesCell.textContent.trim();
1013                const sales = parseInt(salesText.replace(/\s/g, ''));
1014                if (isNaN(sales)) continue;
1015                
1016                // Calculate revenue
1017                const revenue = price * sales;
1018                
1019                if (revenue > 0) {
1020                    competitors.push({
1021                        brand: brand,
1022                        sku: sku,
1023                        price: price,
1024                        sales30days: sales,
1025                        revenue30days: revenue
1026                    });
1027                    
1028                    console.log(`Competitor: ${brand} - Price: ${price}₽, Sales: ${sales}, Revenue: ${revenue}`);
1029                }
1030                
1031            } catch (error) {
1032                console.error(`Error extracting competitor from row ${i}:`, error);
1033            }
1034        }
1035        
1036        // Sort by revenue (descending)
1037        competitors.sort((a, b) => b.revenue30days - a.revenue30days);
1038        
1039        console.log(`Extracted ${competitors.length} competitors from search (excluding our product)`);
1040        console.log('>>> COMPETITOR PRICES EXTRACTED <<<');
1041        console.log('Competitor count:', competitors.length);
1042        if (competitors.length > 0) {
1043            const prices = competitors.map(c => c.price);
1044            const minCompPrice = Math.min(...prices);
1045            const maxCompPrice = Math.max(...prices);
1046            const avgCompPrice = Math.round(prices.reduce((a, b) => a + b, 0) / prices.length);
1047            console.log('Price range:', minCompPrice, '-', maxCompPrice, '₽');
1048            console.log('Average price:', avgCompPrice, '₽');
1049            console.log('All competitor prices:', prices);
1050            console.log('Top 5 competitors by revenue:', competitors.slice(0, 5).map(c => `${c.brand}: ${c.price}₽, ${c.sales30days} шт, ${c.revenue30days}`));
1051        }
1052        
1053        // Save competitors to storage
1054        await GM.setValue('temp_competitors', JSON.stringify(competitors));
1055        console.log('Competitors saved to storage');
1056        
1057        // Mark that extraction is complete
1058        await GM.setValue('competitors_extracted', 'true');
1059        
1060        // Close the tab after successful extraction
1061        console.log('Closing competitor search tab...');
1062        setTimeout(() => {
1063            window.close();
1064        }, 1000);
1065    }
1066
1067    // Extract summary data from MP Stats widget
1068    async function extractMPStatsData() {
1069        console.log('Extracting MP Stats summary data...');
1070        
1071        const widget = document.querySelector('.mps-sidebar');
1072        if (!widget) {
1073            console.error('MP Stats widget not found');
1074            return null;
1075        }
1076
1077        const revenueText = widget.textContent.match(/Выручка за 30 суток\s*([\d\s]+)/);
1078        const salesText = widget.textContent.match(/Продаж за 30 суток\s*([\d\s]+)/);
1079        const currentStockText = widget.textContent.match(/Текущий остаток\s*([\d\s]+)/);
1080        
1081        if (revenueText && salesText) {
1082            const revenue = parseInt(revenueText[1].replace(/\s/g, ''));
1083            const sales = parseInt(salesText[1].replace(/\s/g, ''));
1084            
1085            let avgPrice = revenue / sales;
1086            const webPriceWidget = document.querySelector('[data-widget="webPrice"]');
1087            if (webPriceWidget) {
1088                const priceSpans = webPriceWidget.querySelectorAll('span');
1089                const prices = [];
1090                priceSpans.forEach(span => {
1091                    const text = span.textContent.trim();
1092                    const match = text.match(/^(\d[\d\s]*)\s*₽$/);
1093                    if (match) {
1094                        const priceText = match[1].replace(/\s/g, '');
1095                        const parsedPrice = parseInt(priceText);
1096                        if (!isNaN(parsedPrice) && parsedPrice > 100 && parsedPrice < 100000) {
1097                            prices.push(parsedPrice);
1098                        }
1099                    }
1100                });
1101                if (prices.length > 0) {
1102                    avgPrice = Math.min(...prices);
1103                    console.log('Found prices in webPrice:', prices, 'Using minimum:', avgPrice);
1104                }
1105            }
1106            
1107            const currentStock = currentStockText ? parseInt(currentStockText[1].replace(/\s/g, '')) : 0;
1108            
1109            const dataPoints = await extractDailyDataFromChart(widget);
1110            
1111            if (!dataPoints || dataPoints.length === 0) {
1112                console.error('Failed to extract chart data');
1113                return null;
1114            }
1115
1116            const stockPoints = await extractStockData(widget);
1117            console.log('Stock points extracted:', stockPoints);
1118
1119            const totalSales = dataPoints.reduce((sum, d) => sum + d.sales, 0);
1120            const avgDailySales = totalSales / dataPoints.length;
1121            
1122            let matchedStockPoints = null;
1123            if (stockPoints && stockPoints.length > 0) {
1124                console.log('Matching stock data with sales data...');
1125                matchedStockPoints = dataPoints.map(salesDay => {
1126                    const stockDay = stockPoints.find(s => s.day === salesDay.day);
1127                    return {
1128                        day: salesDay.day,
1129                        sales: salesDay.sales,
1130                        price: salesDay.price,
1131                        stock: stockDay ? stockDay.stock : null
1132                    };
1133                });
1134                console.log('Matched stock data - First 5 days:', matchedStockPoints.slice(0, 5));
1135                console.log('Matched stock data - Last 5 days:', matchedStockPoints.slice(-5));
1136            } else {
1137                console.log('No stock data to match');
1138            }
1139            
1140            console.log('Extracted summary data:', { 
1141                revenue, 
1142                sales,
1143                avgPrice, 
1144                currentStock, 
1145                avgDailySales,
1146                daysOfData: dataPoints.length,
1147                stockDataPoints: stockPoints ? stockPoints.length : 0,
1148                matchedDataPoints: matchedStockPoints ? matchedStockPoints.length : 0
1149            });
1150            
1151            return {
1152                revenue,
1153                sales,
1154                avgPrice,
1155                currentStock,
1156                avgDailySales,
1157                dataPoints,
1158                stockPoints,
1159                matchedStockPoints
1160            };
1161        }
1162
1163        return null;
1164    }
1165
1166    // Calculate demand elasticity from historical data
1167    function calculateDemandElasticity(dataPoints, matchedStockPoints) {
1168        console.log('=== CALCULATING DEMAND ELASTICITY (Bayesian Log-Linear) ===');
1169        console.log('dataPoints:', dataPoints);
1170        console.log('matchedStockPoints:', matchedStockPoints);
1171        
1172        // NEW: Filter outliers first
1173        let filteredPoints = filterOutliers(dataPoints);
1174        console.log(`Using ${filteredPoints.length} points after outlier filtering`);
1175        
1176        // Filter out days with zero stock and the day before zero stock
1177        let validPoints = filteredPoints;
1178        if (matchedStockPoints && matchedStockPoints.length > 0) {
1179            const zeroStockDays = new Set();
1180            matchedStockPoints.forEach((d, index) => {
1181                if (d.stock === 0) {
1182                    zeroStockDays.add(d.day);
1183                    // Also exclude the day before zero stock
1184                    if (index > 0) {
1185                        zeroStockDays.add(matchedStockPoints[index - 1].day);
1186                    }
1187                }
1188            });
1189            validPoints = filteredPoints.filter(d => !zeroStockDays.has(d.day));
1190            console.log(`Excluded ${zeroStockDays.size} days (zero stock and day before)`);
1191        }
1192        
1193        console.log(`Using ${validPoints.length} days for elasticity calculation`);
1194        console.log('Valid points sample:', validPoints.slice(0, 5));
1195        
1196        if (validPoints.length < 5) {
1197            console.log('Not enough data points for elasticity calculation, using default -1.5');
1198            return { elasticity: -1.5, reliability: 'bad', r2: 0, uniquePrices: 0, daysUsed: validPoints.length };
1199        }
1200        
1201        // === LOG-LINEAR REGRESSION ===
1202        // Transform to log space: log(sales) = intercept + elasticity * log(price)
1203        const logPrices = validPoints.map(d => Math.log(d.price));
1204        const logSales = validPoints.map(d => Math.log(d.sales + 1)); // +1 for stability when sales = 0
1205        
1206        const n = validPoints.length;
1207        const sumX = logPrices.reduce((a, b) => a + b, 0);
1208        const sumY = logSales.reduce((a, b) => a + b, 0);
1209        const sumXY = logPrices.reduce((a, b, i) => a + b * logSales[i], 0);
1210        const sumX2 = logPrices.reduce((a, b) => a + b * b, 0);
1211        
1212        console.log(`Log-linear regression: n=${n}, sumX=${sumX.toFixed(2)}, sumY=${sumY.toFixed(2)}, sumXY=${sumXY.toFixed(2)}, sumX2=${sumX2.toFixed(2)}`);
1213        
1214        const denominator = n * sumX2 - sumX * sumX;
1215        if (denominator === 0) {
1216            console.log('⚠️ Denominator is zero, using default elasticity');
1217            return { elasticity: -1.5, reliability: 'bad', r2: 0, uniquePrices: 0, daysUsed: n };
1218        }
1219        
1220        const slope = (n * sumXY - sumX * sumY) / denominator; // This is the elasticity
1221        const intercept = (sumY - slope * sumX) / n;
1222        
1223        console.log(`OLS results: slope (elasticity) = ${slope.toFixed(4)}, intercept = ${intercept.toFixed(4)}`);
1224        
1225        // Calculate R² (coefficient of determination)
1226        const yMean = sumY / n;
1227        const ssTotal = logSales.reduce((s, y) => s + Math.pow(y - yMean, 2), 0);
1228        const predicted = logPrices.map(x => slope * x + intercept);
1229        const ssResidual = logSales.reduce((s, y, i) => s + Math.pow(y - predicted[i], 2), 0);
1230        const r2 = ssTotal > 0 ? 1 - (ssResidual / ssTotal) : 0;
1231        
1232        console.log(`R²: ssTotal=${ssTotal.toFixed(4)}, ssResidual=${ssResidual.toFixed(4)}, R²=${r2.toFixed(4)}`);
1233        
1234        // === BAYESIAN CORRECTION WITH INFORMATIVE PRIOR ===
1235        const priorElasticity = -1.5;        // Typical value for Ozon products
1236        const priorStrength = 10;            // "Equivalent to 10 days of observations"
1237        
1238        console.log(`Prior: elasticity=${priorElasticity}, strength=${priorStrength} days`);
1239        
1240        const dataStrength = n;              // Weight of actual data
1241        const posteriorElasticity = (slope * dataStrength + priorElasticity * priorStrength) / (dataStrength + priorStrength);
1242        
1243        console.log(`Posterior elasticity (simple Bayesian average): ${posteriorElasticity.toFixed(4)}`);
1244        
1245        // If we have a lot of data and high R² - trust the data more
1246        const weightData = Math.min(1, n / 20) * Math.sqrt(Math.max(0, r2));
1247        const finalElasticity = slope * weightData + posteriorElasticity * (1 - weightData);
1248        
1249        console.log(`Data weight: ${weightData.toFixed(4)} (based on n=${n} and R²=${r2.toFixed(4)})`);
1250        console.log(`Final elasticity (weighted): ${finalElasticity.toFixed(4)}`);
1251        
1252        // NEW: Improved clamping with better bounds
1253        // Elasticity should be negative (demand curve slopes down)
1254        // Typical range for e-commerce: -0.5 to -2.5
1255        // Only clamp to extreme values if really necessary
1256        let clampedElasticity = finalElasticity;
1257        
1258        // If elasticity is positive (wrong direction), use prior
1259        if (finalElasticity > 0) {
1260            console.log(`⚠️ Positive elasticity ${finalElasticity.toFixed(4)} detected, using prior ${priorElasticity}`);
1261            clampedElasticity = priorElasticity;
1262        }
1263        // If elasticity is too extreme (< -2.5), clamp it
1264        else if (finalElasticity < -2.5) {
1265            console.log(`⚠️ Extreme elasticity ${finalElasticity.toFixed(4)} detected, clamping to -2.5`);
1266            clampedElasticity = -2.5;
1267        }
1268        // If elasticity is too weak (> -0.3), clamp it
1269        else if (finalElasticity > -0.3) {
1270            console.log(`⚠️ Very weak elasticity ${finalElasticity.toFixed(4)} detected, clamping to -0.5`);
1271            clampedElasticity = -0.5;
1272        }
1273        
1274        // Determine reliability based on R², number of unique prices, and days
1275        const uniquePrices = [...new Set(validPoints.map(d => d.price))];
1276        
1277        let reliability = 'bad';
1278        if (r2 >= 0.7 && uniquePrices.length >= 8 && n >= 20) {
1279            reliability = 'good';
1280        } else if (r2 >= 0.4 && uniquePrices.length >= 4 && n >= 10) {
1281            reliability = 'satisfactory';
1282        }
1283        
1284        console.log(`=== FINAL ELASTICITY: ${clampedElasticity.toFixed(4)}, R²=${r2.toFixed(4)}, Reliability=${reliability} ===`);
1285        console.log(`Raw OLS elasticity: ${slope.toFixed(4)}, Posterior: ${posteriorElasticity.toFixed(4)}, Final: ${clampedElasticity.toFixed(4)}`);
1286        
1287        return { 
1288            elasticity: clampedElasticity, 
1289            reliability: reliability, 
1290            r2: r2, 
1291            uniquePrices: uniquePrices.length, 
1292            daysUsed: n,
1293            rawElasticity: slope,
1294            posteriorElasticity: posteriorElasticity
1295        };
1296    }
1297
1298    // AI-powered Bayesian price optimization
1299    async function bayesianPriceOptimizationWithAI(historicalData, productData, competitorData, coinvest, drr) {
1300        console.log('=== ENTERED bayesianPriceOptimizationWithAI (v2.0.1) ===');
1301        console.log('Historical data:', historicalData);
1302        console.log('Product data:', productData);
1303        console.log('Competitor data:', competitorData);
1304        console.log('Coinvest:', coinvest, '%, DRR:', drr, '%');
1305        
1306        try {
1307            console.log('>>> ABOUT TO CALL calculateDemandElasticity <<<');
1308            console.log('>>> dataPoints:', historicalData.dataPoints);
1309            console.log('>>> matchedStockPoints:', historicalData.matchedStockPoints);
1310            
1311            const elasticityResult = calculateDemandElasticity(historicalData.dataPoints, historicalData.matchedStockPoints);
1312            const realElasticity = elasticityResult.elasticity;
1313            
1314            console.log(`>>> AFTER calculateDemandElasticity, realElasticity = ${realElasticity} <<<`);
1315            console.log(`Real demand elasticity calculated: ${realElasticity.toFixed(4)}, R²=${elasticityResult.r2.toFixed(4)}, Reliability=${elasticityResult.reliability}`);
1316            
1317            // Prepare historical data summary
1318            const uniquePrices = [...new Set(historicalData.dataPoints.map(d => d.price))];
1319            
1320            console.log(`Historical data: ${historicalData.dataPoints.length} days, ${uniquePrices.length} unique prices:`, uniquePrices);
1321            
1322            // === NEW: Calculate market constraints ===
1323            const displayPriceMultiplier = (100 - coinvest) / 100;
1324            const costPrice = (productData.cost + productData.delivery) / (1 - productData.commission - drr / 100);
1325            const minBreakevenDisplayPrice = Math.ceil(costPrice * displayPriceMultiplier);
1326            
1327            let minMarketPrice = minBreakevenDisplayPrice;
1328            let maxMarketPrice = 30000;
1329            
1330            // === NEW: Check if we're market leader ===
1331            let isMarketLeader = false;
1332            let ourRevenue = historicalData.avgPrice * historicalData.sales;
1333            
1334            if (competitorData && competitorData.length > 0) {
1335                const competitorPrices = competitorData.map(c => c.price);
1336                const minCompPrice = Math.min(...competitorPrices);
1337                const maxCompPrice = Math.max(...competitorPrices);
1338                
1339                // Check if our revenue is higher than all competitors
1340                const maxCompetitorRevenue = Math.max(...competitorData.map(c => c.revenue30days || 0));
1341                ourRevenue = historicalData.sales * historicalData.avgPrice; // 30-day revenue
1342                
1343                if (ourRevenue > maxCompetitorRevenue * 0.9) {
1344                    isMarketLeader = true;
1345                    console.log('🏆 MARKET LEADER DETECTED!');
1346                    console.log(`Our revenue: ${ourRevenue.toFixed(0)}₽/30d vs Max competitor: ${maxCompetitorRevenue.toFixed(0)}₽/30d`);
1347                }
1348                
1349                minMarketPrice = Math.max(minBreakevenDisplayPrice, Math.floor(minCompPrice * 0.7));
1350                maxMarketPrice = Math.min(30000, Math.ceil(maxCompPrice * 1.3));
1351                
1352                console.log('=== MARKET CONSTRAINTS ===');
1353                console.log(`Competitor price range: ${minCompPrice}-${maxCompPrice}`);
1354                console.log(`Market boundaries (0.7x - 1.3x): ${Math.floor(minCompPrice * 0.7)} - ${Math.ceil(maxCompPrice * 1.3)}`);
1355                console.log(`Cost-based minimum: ${minBreakevenDisplayPrice}`);
1356                console.log(`FINAL HARD LIMITS: ${minMarketPrice} - ${maxMarketPrice}`);
1357                console.log(`Market Leader Status: ${isMarketLeader ? 'YES 🏆' : 'NO'}`);
1358            } else {
1359                console.log('=== MARKET CONSTRAINTS (No Competitors) ===');
1360                console.log(`HARD LIMITS: ${minMarketPrice} - ${maxMarketPrice}`);
1361            }
1362            
1363            // === NEW: Determine product segment ===
1364            const segmentInfo = determineProductSegment(historicalData.avgPrice, competitorData);
1365            
1366            // === NEW: Calculate inventory strategy ===
1367            const daysOfSupply = historicalData.avgDailySales > 0 ? historicalData.currentStock / historicalData.avgDailySales : 999;
1368            const inventoryInfo = getInventoryStrategy(daysOfSupply);
1369            
1370            // Prepare competitor analysis
1371            let competitorAnalysis = '';
1372            if (competitorData && competitorData.length > 0) {
1373                const prices = competitorData.map(c => c.price);
1374                const minCompPrice = Math.min(...prices);
1375                const maxCompPrice = Math.max(...prices);
1376                const avgCompPrice = Math.round(prices.reduce((a, b) => a + b, 0) / prices.length);
1377                
1378                const topCompetitors = competitorData.slice(0, 3).map(c => 
1379                    `${c.price}₽ (${c.sales30days ? (c.sales30days / 30).toFixed(1) + ' шт/день' : 'н/д'})`
1380                ).join(', ');
1381                
1382                competitorAnalysis = `\nКОНКУРЕНТЫ (${competitorData.length} шт): цены ${minCompPrice}-${maxCompPrice}₽, средняя ${avgCompPrice}₽. Топ-3 по выручке: ${topCompetitors}.`;
1383                
1384                console.log('>>> COMPETITOR PRICES BEING SENT TO AI <<<');
1385                console.log('Competitor count:', competitorData.length);
1386                console.log('Price range:', minCompPrice, '-', maxCompPrice, '₽');
1387                console.log('Average price:', avgCompPrice, '₽');
1388                console.log('Top 3 competitors:', topCompetitors);
1389                console.log('All competitor prices:', prices);
1390                console.log('Competitor analysis text for AI:', competitorAnalysis);
1391            } else {
1392                console.log('>>> NO COMPETITOR DATA - AI WILL NOT CONSIDER COMPETITORS <<<');
1393            }
1394
1395            const commissionPercent = Math.round(productData.commission * 100);
1396            
1397            // Calculate actual price from current display price using user's coinvest value
1398            const actualPrice = historicalData.avgPrice / displayPriceMultiplier;
1399            
1400            // === НОВЫЕ МЕТРИКИ ===
1401            
1402            // 1. Weighted average competitor price (взвешенная по продажам)
1403            let weightedAvgCompPrice = 0;
1404            let totalCompSales = 0;
1405            let minCompPrice = Infinity;
1406            let maxCompPrice = 0;
1407            if (competitorData && competitorData.length > 0) {
1408                competitorData.forEach(c => {
1409                    if (c.sales30days > 0) {
1410                        weightedAvgCompPrice += c.price * c.sales30days;
1411                        totalCompSales += c.sales30days;
1412                    }
1413                    minCompPrice = Math.min(minCompPrice, c.price);
1414                    maxCompPrice = Math.max(maxCompPrice, c.price);
1415                });
1416                weightedAvgCompPrice = totalCompSales > 0 ? weightedAvgCompPrice / totalCompSales : historicalData.avgPrice;
1417            } else {
1418                weightedAvgCompPrice = historicalData.avgPrice;
1419                minCompPrice = historicalData.avgPrice;
1420                maxCompPrice = historicalData.avgPrice;
1421            }
1422            
1423            // 2. RPI (Relative Price Index)
1424            const currentDisplayPrice = historicalData.avgPrice;
1425            const rpi = (currentDisplayPrice / weightedAvgCompPrice) * 100;
1426            
1427            // 3. Popularity Score (твои средние продажи vs средние конкурентов)
1428            let avgCompDailySales = 0;
1429            if (competitorData && competitorData.length > 0) {
1430                avgCompDailySales = competitorData.reduce((sum, c) => sum + (c.sales30days || 0) / 30, 0) / competitorData.length;
1431            }
1432            const popularityScore = avgCompDailySales > 0 ? historicalData.avgDailySales / avgCompDailySales : 1;
1433            
1434            // 4. PVBI (Price Value Benefit Index) — proxy ценности
1435            let maxCompValue = 0;
1436            if (competitorData && competitorData.length > 0) {
1437                competitorData.forEach(c => {
1438                    const value = c.sales30days > 0 ? (c.sales30days / 30) / c.price : 0;
1439                    maxCompValue = Math.max(maxCompValue, value);
1440                });
1441            }
1442            const yourValue = historicalData.avgDailySales / currentDisplayPrice;
1443            const pvbi = maxCompValue > 0 ? yourValue / maxCompValue : 1;
1444            
1445            // 6. Топ-3 конкурентов для промпта
1446            const topCompetitors = competitorData && competitorData.length > 0 
1447                ? competitorData.slice(0, 3).map(c => 
1448                    `${c.brand}: ${c.price}₽ (${(c.sales30days / 30).toFixed(1)} шт/день)`
1449                ).join(', ')
1450                : 'нет данных';
1451            
1452            console.log('=== НОВЫЕ МЕТРИКИ ===');
1453            console.log('Weighted Avg Comp Price:', weightedAvgCompPrice.toFixed(0), '₽');
1454            console.log('RPI:', rpi.toFixed(1), '%');
1455            console.log('Popularity Score:', popularityScore.toFixed(2));
1456            console.log('PVBI:', pvbi.toFixed(2));
1457            console.log('Days of Supply:', daysOfSupply.toFixed(1));
1458            
1459            const aiPrompt = `Ты — эксперт по динамическому ценообразованию на маркетплейсах (Ozon). Твоя задача — найти цену реализации, которая МАКСИМИЗИРУЕТ ДНЕВНУЮ ПРИБЫЛЬ с учётом всех рисков.
1460
1461⚠️ ЖЁСТКИЕ ОГРАНИЧЕНИЯ (НИКОГДА НЕ НАРУШАЙ):
1462• Минимальная цена реализации: ${minMarketPrice} ₽ (безубыточность + рыночный минимум)
1463• Максимальная цена реализации: ${maxMarketPrice} ₽ (рыночный максимум)
1464• ВСЕ рекомендуемые цены ДОЛЖНЫ быть в диапазоне [${minMarketPrice}, ${maxMarketPrice}] ₽
1465• Если расчёт даёт цену вне диапазона — используй ближайшую границу
1466
1467${isMarketLeader ? `
1468🏆 КРИТИЧЕСКИ ВАЖНО - ВЫ ЛИДЕР РЫНКА:
1469• Ваша выручка (${Math.round(ourRevenue)}₽/30д) ВЫШЕ всех конкурентов
1470• Вы уже занимаете доминирующую позицию на рынке
1471• Снижение цены приведёт к ПОТЕРЕ ПРИБЫЛИ без существенного роста продаж
1472• Конкуренты с низкими ценами имеют МЕНЬШУЮ выручку - их стратегия НЕ эффективнее вашей
1473• ЗАПРЕЩЕНО рекомендовать снижение цены более чем на 5% от текущей
1474• Приоритет: СОХРАНЕНИЕ МАРЖИНАЛЬНОСТИ, а не рост объёма продаж
1475` : ''}
1476
1477КРИТИЧЕСКИ ВАЖНО:
1478• Цена реализации — это цена, которую видит покупатель (после соинвеста ${coinvest}% от Ozon).
1479• Фактическая цена = Цена реализации / ${displayPriceMultiplier.toFixed(2)}.
1480• Все расходы (комиссия, ДРР) считаются от фактической цены.
1481• Прибыль = (Факт. цена - Себестоимость - Комиссия - Доставка - Реклама) × Прогноз продаж.
1482
1483ТЕКУЩАЯ СИТУАЦИЯ:
1484• Текущая цена реализации: ${Math.round(historicalData.avgPrice)}1485• Фактическая цена: ${Math.round(actualPrice)}1486• Средние продажи: ${historicalData.avgDailySales.toFixed(1)} шт/день
1487• Остаток: ${historicalData.currentStock} шт (Days of Supply: ${daysOfSupply.toFixed(1)} дней)
1488• Popularity Score (относительно конкурентов): ${popularityScore.toFixed(2)} (выше 1 — популярнее рынка)
1489• RPI (Relative Price Index): ${rpi.toFixed(1)}% (100% — средняя цена конкурентов по выручке)
1490• PVBI (Price Value Benefit Index): ${pvbi.toFixed(2)}
1491
1492ПОЗИЦИОНИРОВАНИЕ ТОВАРА:
1493• Сегмент: ${segmentInfo.segment}${segmentInfo.description}
1494• Стратегия: ${segmentInfo.strategy}
1495
1496СТРАТЕГИЯ ПО ОСТАТКАМ:
1497• Статус: ${inventoryInfo.action} (${inventoryInfo.daysOfSupply.toFixed(1)} дней)
1498• Рекомендация: ${inventoryInfo.priceAdjustment}
1499
1500ЭЛАСТИЧНОСТЬ СПРОСА (лог-линейная модель, ${historicalData.dataPoints.length} дней, ${uniquePrices.length} уникальных цен):
1501• Коэффициент эластичности: ${realElasticity.toFixed(4)}
1502• Формула прогноза: Прогноз продаж = ${historicalData.avgDailySales.toFixed(1)} × (цена / ${Math.round(historicalData.avgPrice)}) ** ${realElasticity.toFixed(4)}
1503• Достоверность: R² = ${elasticityResult.r2.toFixed(4)}, ${elasticityResult.reliability}
1504
1505СТРУКТУРА РАСХОДОВ:
1506• Себестоимость: ${productData.cost}1507• Комиссия Ozon: ${commissionPercent}% от факт. цены
1508• Доставка: ${productData.delivery}1509• ДРР: ${drr}% от факт. цены
1510• Минимальная безубыточная цена реализации: ${minBreakevenDisplayPrice}1511
1512КОНКУРЕНТЫ (${competitorData ? competitorData.length : 0} шт):
1513• Взвешенная средняя цена: ${Math.round(weightedAvgCompPrice)}1514• Диапазон: ${minCompPrice === Infinity ? 'н/д' : minCompPrice + '–' + maxCompPrice + ' ₽'}
1515• Топ-3 по выручке: ${topCompetitors}
1516
1517БИЗНЕС-ЛОГИКА (обязательно применяй):
15181. УБЫТОЧНОСТЬ: Никогда не рекомендуй цену ниже ${minBreakevenDisplayPrice} ₽ (себестоимость + расходы)
15192. КОНКУРЕНТОСПОСОБНОСТЬ: Учитывай позицию относительно конкурентов (RPI, сегмент)
15203. ЛИКВИДНОСТЬ: При высоких остатках (>90 дней) приоритет — скорость продаж, при низких (<30) — маржа
15214. ЭЛАСТИЧНОСТЬ: Используй реальную эластичность ${realElasticity.toFixed(4)} для прогноза продаж
15225. РЫНОЧНЫЕ ГРАНИЦЫ: Цена вне [${minMarketPrice}, ${maxMarketPrice}] ₽ нереалистична для этого рынка
1523${isMarketLeader ? '6. ЛИДЕРСТВО: Как лидер рынка, ты НЕ ДОЛЖЕН снижать цену без крайней необходимости (критические остатки >180 дней)' : ''}
1524
1525ДОПОЛНИТЕЛЬНЫЕ КОРРЕКТИРОВКИ:
15261. RPI-корректировка: если RPI > 110 — уменьши прогноз продаж на (RPI-100)/50; если RPI < 90 — увеличь на (100-RPI)/50.
15272. Остатки: ${inventoryInfo.priceAdjustment}
15283. Popularity Score: если > 1.2 — можно устанавливать цену выше рынка без сильного падения продаж.
15294. Сегмент: ${segmentInfo.strategy}
1530
1531ТВОЯ ЗАДАЧА:
15321. Рассчитай прибыль для цен реализации от ${minMarketPrice} ₽ до ${maxMarketPrice} ₽ с шагом 10 ₽.
15332. Для каждой цены применяй ВСЕ корректировки выше (RPI, остатки, популярность, сегмент).
15343. Используй лог-линейную формулу: Прогноз = ${historicalData.avgDailySales.toFixed(1)} × (цена / ${Math.round(historicalData.avgPrice)}) ** ${realElasticity.toFixed(4)}
15354. Выбери цену с МАКСИМАЛЬНОЙ дневной прибылью В ДИАПАЗОНЕ [${minMarketPrice}, ${maxMarketPrice}] ₽.
15365. Также предложи 3 альтернативные цены для исследования (explorationPrices) — чуть ниже/выше оптимума, но СТРОГО в диапазоне.
1537${isMarketLeader ? `
15386. ⚠️ ОСОБОЕ ПРАВИЛО ДЛЯ ЛИДЕРА: Если оптимальная цена ниже текущей более чем на 5%, ИГНОРИРУЙ её и рекомендуй текущую цену или выше. Лидер рынка НЕ должен демпинговать.
1539` : ''}
1540
1541ВАЖНО: 
1542• Не бойся рекомендовать изменение цены! Если расчеты показывают, что другая цена даст больше прибыли - рекомендуй её!
1543${isMarketLeader ? '• НО: Как лидер рынка, снижение цены должно быть обосновано КРИТИЧЕСКОЙ необходимостью (остатки >180 дней), а не просто "возможным ростом продаж"' : ''}
1544• ВСЕ цены (optimalPrice, minPrice, maxPrice, explorationPrices) ДОЛЖНЫ быть в диапазоне [${minMarketPrice}, ${maxMarketPrice}] ₽!
1545
1546Верни JSON строго по схеме с оптимальной ценой РЕАЛИЗАЦИИ (той, что дает максимальную прибыль/день).`;
1547
1548            console.log('>>> CALLING RM.aiCall <<<');
1549            const aiResponse = await RM.aiCall(aiPrompt, {
1550                type: 'json_schema',
1551                json_schema: {
1552                    name: 'price_optimization',
1553                    schema: {
1554                        type: 'object',
1555                        properties: {
1556                            optimalPrice: { type: 'number' },
1557                            minPrice: { type: 'number' },
1558                            maxPrice: { type: 'number' },
1559                            confidence: { type: 'number' },
1560                            reasoning: { type: 'string' },
1561                            explorationPrices: {
1562                                type: 'array',
1563                                items: { type: 'number' },
1564                                minItems: 3,
1565                                maxItems: 3
1566                            }
1567                        },
1568                        required: ['optimalPrice', 'minPrice', 'maxPrice', 'confidence', 'reasoning', 'explorationPrices']
1569                    }
1570                }
1571            });
1572
1573            console.log('>>> AI RESPONSE RECEIVED <<<');
1574            console.log('AI response:', aiResponse);
1575            console.log('AI optimalPrice:', aiResponse.optimalPrice);
1576            console.log('AI reasoning:', aiResponse.reasoning);
1577            console.log('AI confidence:', aiResponse.confidence);
1578            console.log('AI explorationPrices:', aiResponse.explorationPrices);
1579
1580            // === NEW: Post-process AI recommendations to enforce market constraints ===
1581            let correctionWarning = '';
1582            
1583            // Clamp optimal price to market boundaries
1584            const originalOptimalPrice = aiResponse.optimalPrice;
1585            if (aiResponse.optimalPrice < minMarketPrice) {
1586                aiResponse.optimalPrice = minMarketPrice;
1587                correctionWarning = `⚠️ КОРРЕКЦИЯ: AI предложил ${originalOptimalPrice}₽, но это ниже минимальной рыночной границы. Цена скорректирована до ${minMarketPrice}₽ (минимум рынка).`;
1588                console.log(correctionWarning);
1589            } else if (aiResponse.optimalPrice > maxMarketPrice) {
1590                aiResponse.optimalPrice = maxMarketPrice;
1591                correctionWarning = `⚠️ КОРРЕКЦИЯ: AI предложил ${originalOptimalPrice}₽, но это выше максимальной рыночной границы. Цена скорректирована до ${maxMarketPrice}₽ (максимум рынка).`;
1592                console.log(correctionWarning);
1593            }
1594            
1595            // Clamp exploration prices
1596            aiResponse.explorationPrices = aiResponse.explorationPrices.map(price => {
1597                return Math.max(minMarketPrice, Math.min(maxMarketPrice, price));
1598            });
1599            
1600            // Clamp min/max prices
1601            aiResponse.minPrice = Math.max(minMarketPrice, Math.min(maxMarketPrice, aiResponse.minPrice));
1602            aiResponse.maxPrice = Math.max(minMarketPrice, Math.min(maxMarketPrice, aiResponse.maxPrice));
1603            
1604            // Add warning to reasoning if correction was made
1605            if (correctionWarning) {
1606                aiResponse.reasoning = correctionWarning + '\n\n' + aiResponse.reasoning;
1607            }
1608
1609            // Calculate all possible prices and find the one with maximum profit
1610            const priceRange = [];
1611            const step = (aiResponse.maxPrice - aiResponse.minPrice) / 20;
1612            
1613            for (let price = aiResponse.minPrice; price <= aiResponse.maxPrice; price += step) {
1614                priceRange.push(Math.round(price));
1615            }
1616            
1617            aiResponse.explorationPrices.forEach(p => {
1618                if (!priceRange.includes(Math.round(p))) {
1619                    priceRange.push(Math.round(p));
1620                }
1621            });
1622            
1623            priceRange.sort((a, b) => a - b);
1624
1625            const results = priceRange.map(displayPrice => {
1626                let estimatedSales = historicalData.avgDailySales * Math.pow(displayPrice / historicalData.avgPrice, realElasticity);
1627                
1628                // Calculate actual price from display price using user's coinvest
1629                const actualPrice = displayPrice / displayPriceMultiplier;
1630                const commission = actualPrice * productData.commission;
1631                const advertisingCost = actualPrice * (drr / 100);
1632                const delivery = productData.delivery;
1633                const profitPerUnit = actualPrice - productData.cost - commission - delivery - advertisingCost;
1634                const profit = profitPerUnit * estimatedSales;
1635                const margin = (profitPerUnit / actualPrice) * 100;
1636                
1637                return {
1638                    price: Math.round(displayPrice * 10) / 10,
1639                    actualPrice: Math.round(actualPrice * 10) / 10,
1640                    estimatedDailySales: Math.round(estimatedSales * 10) / 10,
1641                    estimatedDailyProfit: Math.round(profit * 10) / 10,
1642                    profitMargin: Math.round(margin * 10) / 10,
1643                    confidence: aiResponse.confidence,
1644                    commission: Math.round(commission * 10) / 10,
1645                    advertisingCost: Math.round(advertisingCost * 10) / 10,
1646                    delivery: delivery
1647                };
1648            });
1649
1650            // Find the price with maximum profit from our calculations
1651            const maxProfitResult = results.reduce((max, current) => 
1652                current.estimatedDailyProfit > max.estimatedDailyProfit ? current : max
1653            );
1654            
1655            console.log('>>> CALCULATED OPTIMAL PRICE <<<');
1656            console.log('Current price:', historicalData.avgPrice, '₽');
1657            console.log('AI suggested:', aiResponse.optimalPrice, '₽');
1658            console.log('Math optimal:', maxProfitResult.price, '₽ with profit:', maxProfitResult.estimatedDailyProfit, '₽/day');
1659            
1660            // Log all results sorted by profit
1661            const sortedByProfit = [...results].sort((a, b) => b.estimatedDailyProfit - a.estimatedDailyProfit);
1662            console.log('>>> TOP 10 PRICES BY PROFIT <<<');
1663            sortedByProfit.slice(0, 10).forEach((r, i) => {
1664                console.log(`${i + 1}. Price: ${r.price}₽, Profit: ${r.estimatedDailyProfit}₽/day, Sales: ${r.estimatedDailySales} шт/day, Margin: ${r.profitMargin}%`);
1665            });
1666            
1667            console.log('>>> BOTTOM 5 PRICES BY PROFIT <<<');
1668            sortedByProfit.slice(-5).forEach((r, i) => {
1669                console.log(`${sortedByProfit.length - 4 + i}. Price: ${r.price}₽, Profit: ${r.estimatedDailyProfit}₽/day, Sales: ${r.estimatedDailySales} шт/day`);
1670            });
1671            
1672            // Use the mathematically optimal price instead of AI suggestion
1673            let optimalResult = maxProfitResult;
1674            
1675            // NEW: Check if optimal price actually gives more profit than current price
1676            // Calculate current profit correctly
1677            const currentActualPriceCalc = historicalData.avgPrice / displayPriceMultiplier;
1678            const currentCommissionCalc = currentActualPriceCalc * productData.commission;
1679            const currentAdvertisingCostCalc = currentActualPriceCalc * (drr / 100);
1680            const currentDeliveryCalc = productData.delivery;
1681            const currentProfitPerUnitCalc = currentActualPriceCalc - productData.cost - currentCommissionCalc - currentDeliveryCalc - currentAdvertisingCostCalc;
1682            const currentDailyProfitCalc = Math.round(currentProfitPerUnitCalc * historicalData.avgDailySales * 10) / 10;
1683            
1684            console.log('>>> COMPARING OPTIMAL VS CURRENT <<<');
1685            console.log('Current daily profit:', currentDailyProfitCalc, '₽/day');
1686            console.log('Optimal daily profit:', maxProfitResult.estimatedDailyProfit, '₽/day');
1687            console.log('Difference:', (maxProfitResult.estimatedDailyProfit - currentDailyProfitCalc).toFixed(1), '₽/day');
1688            console.log('Percentage improvement:', ((maxProfitResult.estimatedDailyProfit / currentDailyProfitCalc - 1) * 100).toFixed(2), '%');
1689            
1690            // NEW: More strict check - if profit improvement is less than 5%, keep current price
1691            const profitImprovement = (maxProfitResult.estimatedDailyProfit / currentDailyProfitCalc - 1) * 100;
1692            
1693            if (profitImprovement < 5) {
1694                console.log(`⚠️ WARNING: Profit improvement is only ${profitImprovement.toFixed(2)}% (less than 5% threshold)`);
1695                console.log('Keeping current price as optimal - not worth the risk of changing price for minimal gain');
1696                
1697                // Find result for current price or create it
1698                let currentPriceResult = results.find(r => Math.abs(r.price - historicalData.avgPrice) < 5);
1699                
1700                if (!currentPriceResult) {
1701                    const estimatedSales = historicalData.avgDailySales; // Current sales at current price
1702                    const actualPriceForCurrent = historicalData.avgPrice / displayPriceMultiplier;
1703                    const commissionForCurrent = actualPriceForCurrent * productData.commission;
1704                    const advertisingCostForCurrent = actualPriceForCurrent * (drr / 100);
1705                    const deliveryForCurrent = productData.delivery;
1706                    const profitForCurrent = (actualPriceForCurrent - productData.cost - commissionForCurrent - deliveryForCurrent - advertisingCostForCurrent) * estimatedSales;
1707                    const marginForCurrent = ((actualPriceForCurrent - productData.cost - commissionForCurrent - deliveryForCurrent - advertisingCostForCurrent) / actualPriceForCurrent) * 100;
1708                    
1709                    currentPriceResult = {
1710                        price: Math.round(historicalData.avgPrice * 10) / 10,
1711                        actualPrice: Math.round(actualPriceForCurrent * 10) / 10,
1712                        estimatedDailySales: Math.round(estimatedSales * 10) / 10,
1713                        estimatedDailyProfit: Math.round(profitForCurrent * 10) / 10,
1714                        profitMargin: Math.round(marginForCurrent * 10) / 10,
1715                        confidence: aiResponse.confidence,
1716                        commission: Math.round(commissionForCurrent * 10) / 10,
1717                        advertisingCost: Math.round(advertisingCostForCurrent * 10) / 10,
1718                        delivery: deliveryForCurrent
1719                    };
1720                }
1721                
1722                optimalResult = currentPriceResult;
1723                
1724                const profitDiffAmount = maxProfitResult.estimatedDailyProfit - currentDailyProfitCalc;
1725                aiResponse.reasoning = `⚠️ ВАЖНО: Текущая цена ${Math.round(historicalData.avgPrice)}₽ уже оптимальна. Математический анализ показал, что снижение до ${maxProfitResult.price}₽ увеличит прибыль всего на ${profitDiffAmount.toFixed(1)}₽/день (+${profitImprovement.toFixed(2)}%). Это НЕЗНАЧИТЕЛЬНОЕ улучшение (менее 5%) НЕ оправдывает риски изменения цены: потеря маржинальности (${Math.round(historicalData.avgPrice - maxProfitResult.price)}₽ с каждой продажи), возможные ошибки в прогнозе эластичности, негативное восприятие частых изменений цены покупателями. РЕКОМЕНДАЦИЯ: Сохранить текущую цену ${Math.round(historicalData.avgPrice)}₽ для стабильной максимальной прибыли ${currentDailyProfitCalc}₽/день.`;
1726            }
1727            // Update AI reasoning to reflect the correction
1728            else if (Math.abs(maxProfitResult.price - aiResponse.optimalPrice) > 5) {
1729                const aiSuggestedResult = results.find(r => Math.abs(r.price - aiResponse.optimalPrice) < 1);
1730                const aiSuggestedProfit = aiSuggestedResult ? aiSuggestedResult.estimatedDailyProfit : 0;
1731                
1732                aiResponse.reasoning = `Математический расчет показал, что оптимальная цена ${maxProfitResult.price}₽ дает прибыль ${maxProfitResult.estimatedDailyProfit}₽/день, что лучше первоначально предложенной ${aiResponse.optimalPrice}₽ (прибыль ${aiSuggestedProfit}₽/день) и текущей ${Math.round(historicalData.avgPrice)}₽ (прибыль ${currentDailyProfitCalc}₽/день). При цене ${maxProfitResult.price}₽: продажи ${maxProfitResult.estimatedDailySales} шт/день, маржа ${maxProfitResult.profitMargin}%, прибыль/шт ${Math.round(maxProfitResult.actualPrice - productData.cost - maxProfitResult.commission - maxProfitResult.delivery - maxProfitResult.advertisingCost)}₽. Эта цена максимизирует дневную прибыль с учетом эластичности спроса и конкурентной среды.`;
1733                console.log('>>> CORRECTED AI SUGGESTION <<<');
1734                console.log('New reasoning:', aiResponse.reasoning);
1735            }
1736
1737            const alternatives = [];
1738            aiResponse.explorationPrices.forEach(explorePrice => {
1739                if (explorePrice !== aiResponse.optimalPrice) {
1740                    let altResult = results.find(r => r.price === explorePrice);
1741                    
1742                    if (!altResult) {
1743                        const estimatedSales = historicalData.avgDailySales * Math.pow(explorePrice / historicalData.avgPrice, realElasticity);
1744                        
1745                        const actualPrice = explorePrice / displayPriceMultiplier;
1746                        const commission = actualPrice * productData.commission;
1747                        const advertisingCost = actualPrice * (drr / 100);
1748                        const delivery = productData.delivery;
1749                        const profit = (actualPrice - productData.cost - commission - delivery - advertisingCost) * estimatedSales;
1750                        const margin = ((actualPrice - productData.cost - commission - delivery - advertisingCost) / actualPrice) * 100;
1751                        
1752                        altResult = {
1753                            price: Math.round(explorePrice * 10) / 10,
1754                            actualPrice: Math.round(actualPrice * 10) / 10,
1755                            estimatedDailySales: Math.round(estimatedSales * 10) / 10,
1756                            estimatedDailyProfit: Math.round(profit * 10) / 10,
1757                            profitMargin: Math.round(margin * 10) / 10,
1758                            confidence: aiResponse.confidence,
1759                            commission: Math.round(commission * 10) / 10,
1760                            advertisingCost: Math.round(advertisingCost * 10) / 10,
1761                            delivery: delivery
1762                        };
1763                    }
1764                    
1765                    alternatives.push(altResult);
1766                }
1767            });
1768
1769            console.log('>>> RETURNING OPTIMIZATION RESULTS <<<');
1770            return {
1771                optimal: optimalResult,
1772                alternatives: alternatives,
1773                currentPrice: Math.round(historicalData.avgPrice),
1774                productData: productData,
1775                allResults: results,
1776                aiReasoning: aiResponse.reasoning,
1777                aiConfidence: aiResponse.confidence,
1778                aiDemandElasticity: realElasticity,
1779                elasticityReliability: elasticityResult.reliability,
1780                elasticityR2: elasticityResult.r2,
1781                elasticityUniquePrices: elasticityResult.uniquePrices,
1782                elasticityDaysUsed: elasticityResult.daysUsed,
1783                explorationPrices: aiResponse.explorationPrices,
1784                competitorData: competitorData,
1785                historicalData: historicalData,
1786                coinvest: coinvest,
1787                drr: drr,
1788                segmentInfo: segmentInfo,
1789                inventoryInfo: inventoryInfo,
1790                marketConstraints: { minMarketPrice, maxMarketPrice }
1791            };
1792
1793        } catch (error) {
1794            console.error('AI analysis failed:', error);
1795            throw error;
1796        }
1797    }
1798
1799    // Create and inject the analysis widget
1800    function createAnalysisWidget() {
1801        console.log('Creating analysis widget (v2.0.1)...');
1802        
1803        if (document.getElementById('bayesian-price-optimizer')) {
1804            console.log('Widget already exists');
1805            return;
1806        }
1807
1808        const widget = document.createElement('div');
1809        widget.id = 'bayesian-price-optimizer';
1810        widget.innerHTML = `
1811            <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 
1812                        color: white; 
1813                        padding: 15px; 
1814                        border-radius: 12px; 
1815                        margin: 15px 0; 
1816                        box-shadow: 0 4px 15px rgba(0,0,0,0.2);
1817                        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1818                        width: 100%;
1819                        box-sizing: border-box;">
1820                <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px;">
1821                    <h3 style="margin: 0; font-size: 16px; font-weight: 600;">
1822                        🎯 Оптимизация цены (AI + Bayesian) v2.0.1
1823                    </h3>
1824                </div>
1825                
1826                <div style="margin-bottom: 12px;">
1827                    <label style="display: block; font-size: 12px; margin-bottom: 4px; opacity: 0.9;">
1828                        Ключевой запрос для поиска конкурентов
1829                    </label>
1830                    <input type="text" id="key-query-input" placeholder="Например: крем для лица увлажняющий"
1831                           style="width: 100%; padding: 8px; border: none; border-radius: 6px; 
1832                                  font-size: 14px; box-sizing: border-box;">
1833                </div>
1834                
1835                <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-bottom: 12px;">
1836                    <div>
1837                        <label style="display: block; font-size: 12px; margin-bottom: 4px; opacity: 0.9;">
1838                            Соинвест (скидка OZON), %
1839                        </label>
1840                        <input type="number" id="coinvest-input" value="45" min="0" max="100" step="1"
1841                               style="width: 100%; padding: 8px; border: none; border-radius: 6px; 
1842                                      font-size: 14px; box-sizing: border-box; font-weight: 600;">
1843                    </div>
1844                    <div>
1845                        <label style="display: block; font-size: 12px; margin-bottom: 4px; opacity: 0.9;">
1846                            ДРР (расходы на рекламу), %
1847                        </label>
1848                        <input type="number" id="drr-input" value="0" min="0" max="100" step="0.1"
1849                               style="width: 100%; padding: 8px; border: none; border-radius: 6px; 
1850                                      font-size: 14px; box-sizing: border-box; font-weight: 600;">
1851                    </div>
1852                </div>
1853                
1854                <button id="analyze-price-btn" style="background: white; 
1855                                                       color: #667eea; 
1856                                                       border: none; 
1857                                                       padding: 10px 20px; 
1858                                                       border-radius: 8px; 
1859                                                       cursor: pointer; 
1860                                                       font-weight: 600;
1861                                                       font-size: 14px;
1862                                                       transition: all 0.3s;
1863                                                       width: 100%;">
1864                    Анализировать
1865                </button>
1866                
1867                <div id="analysis-results" style="display: none; margin-top: 15px;">
1868                    <div style="background: rgba(255,255,255,0.15); 
1869                                padding: 12px; 
1870                                border-radius: 8px; 
1871                                backdrop-filter: blur(10px);
1872                                max-width: 600px; box-sizing: border-box;">
1873                        <div id="results-content" style="overflow-wrap: break-word; word-wrap: break-word;"></div>
1874                    </div>
1875                </div>
1876                <div id="loading-indicator" style="display: none; text-align: center; padding: 20px;">
1877                    <div style="display: inline-block; width: 30px; height: 30px; border: 3px solid rgba(255,255,255,0.3); border-top-color: white; border-radius: 50%; animation: spin 1s linear infinite;"></div>
1878                    <p style="margin-top: 10px; font-size: 13px;">Анализируем данные с помощью AI...</p>
1879                </div>
1880            </div>
1881        `;
1882
1883        const style = document.createElement('style');
1884        style.textContent = `
1885            @keyframes spin {
1886                to { transform: rotate(360deg); }
1887            }
1888            #analyze-price-btn:hover {
1889                transform: translateY(-2px);
1890                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
1891            }
1892            #bayesian-price-optimizer * {
1893                box-sizing: border-box;
1894            }
1895        `;
1896        document.head.appendChild(style);
1897
1898        const mpsWidget = document.querySelector('.mps-sidebar');
1899        if (mpsWidget) {
1900            mpsWidget.parentElement.insertBefore(widget, mpsWidget.nextSibling);
1901            console.log('Widget inserted after MP Stats');
1902        } else {
1903            document.body.appendChild(widget);
1904            console.log('Widget inserted at body end');
1905        }
1906
1907        const analyzeBtn = document.getElementById('analyze-price-btn');
1908        analyzeBtn.addEventListener('click', performAnalysis);
1909    }
1910
1911    // Perform the price analysis
1912    async function performAnalysis() {
1913        console.log('>>> performAnalysis CALLED (v2.0.1) <<<');
1914        
1915        const loadingIndicator = document.getElementById('loading-indicator');
1916        const resultsDiv = document.getElementById('analysis-results');
1917        
1918        loadingIndicator.style.display = 'block';
1919        resultsDiv.style.display = 'none';
1920
1921        try {
1922            // Get user input values
1923            const coinvestInput = document.getElementById('coinvest-input');
1924            const drrInput = document.getElementById('drr-input');
1925            const keyQueryInput = document.getElementById('key-query-input');
1926            
1927            const coinvest = parseFloat(coinvestInput.value) || 45;
1928            const drr = parseFloat(drrInput.value) || 0;
1929            const keyQuery = keyQueryInput.value.trim();
1930            
1931            console.log('User inputs - Coinvest:', coinvest, '%, DRR:', drr, '%, Key Query:', keyQuery);
1932            
1933            // Validate inputs
1934            if (coinvest < 0 || coinvest > 100) {
1935                throw new Error('Соинвест должен быть от 0 до 100%');
1936            }
1937            if (drr < 0 || drr > 100) {
1938                throw new Error('ДРР должен быть от 0 до 100%');
1939            }
1940            if (!keyQuery) {
1941                throw new Error('Пожалуйста, введите ключевой запрос для поиска конкурентов');
1942            }
1943            
1944            const productId = getProductId();
1945            console.log('Product ID:', productId);
1946            
1947            if (!productId) {
1948                throw new Error('Не удалось определить ID товара');
1949            }
1950
1951            const shortSku = getShortSku(productId);
1952            console.log('Short SKU:', shortSku);
1953            
1954            if (!shortSku) {
1955                throw new Error('Данные для этого товара не найдены');
1956            }
1957            
1958            const productData = PRODUCT_DATA[shortSku];
1959            console.log('Product data:', productData);
1960            
1961            if (!productData) {
1962                throw new Error('Данные для этого товара не найдены');
1963            }
1964
1965            console.log('>>> CALLING extractMPStatsData <<<');
1966            const mpStatsData = await extractMPStatsData();
1967            console.log('>>> extractMPStatsData FINISHED <<<');
1968            
1969            if (!mpStatsData) {
1970                throw new Error('Не удалось извлечь данные из MP Stats');
1971            }
1972
1973            // Save analysis state before opening search tab
1974            await GM.setValue('analysis_state', JSON.stringify({
1975                coinvest,
1976                drr,
1977                keyQuery,
1978                productId,
1979                shortSku,
1980                mpStatsData,
1981                productData,
1982                timestamp: Date.now()
1983            }));
1984            console.log('Analysis state saved, opening search tab...');
1985
1986            // Clear previous competitor data
1987            await GM.deleteValue('temp_competitors');
1988            await GM.deleteValue('competitors_extracted');
1989
1990            console.log('>>> CALLING extractCompetitorsFromSearch <<<');
1991            await extractCompetitorsFromSearch(keyQuery);
1992            
1993            // Wait for competitors to be extracted (poll for data)
1994            console.log('Waiting for competitor data...');
1995            let attempts = 0;
1996            const maxAttempts = 90; // 90 seconds max (increased from 60)
1997            
1998            while (attempts < maxAttempts) {
1999                await new Promise(resolve => setTimeout(resolve, 1000));
2000                
2001                const extracted = await GM.getValue('competitors_extracted', null);
2002                if (extracted === 'true') {
2003                    console.log('Competitors extracted successfully, continuing analysis...');
2004                    break;
2005                }
2006                
2007                if (extracted === 'failed') {
2008                    throw new Error('Не удалось извлечь данные о конкурентах из MPStats');
2009                }
2010                
2011                attempts++;
2012                if (attempts % 10 === 0) {
2013                    console.log(`Waiting for competitors... ${attempts}/${maxAttempts} seconds`);
2014                }
2015            }
2016            
2017            if (attempts >= maxAttempts) {
2018                throw new Error('Timeout: не удалось получить данные о конкурентах за 90 секунд');
2019            }
2020            
2021            // Get competitors from storage
2022            const competitorsJson = await GM.getValue('temp_competitors', null);
2023            if (!competitorsJson) {
2024                throw new Error('Не удалось получить данные о конкурентах');
2025            }
2026
2027            const competitorData = JSON.parse(competitorsJson);
2028            console.log('Competitors loaded:', competitorData);
2029
2030            // Clear state
2031            await GM.deleteValue('analysis_state');
2032            await GM.deleteValue('temp_competitors');
2033            await GM.deleteValue('competitors_extracted');
2034
2035            console.log('>>> CALLING bayesianPriceOptimizationWithAI <<<');
2036            const optimization = await bayesianPriceOptimizationWithAI(
2037                mpStatsData, 
2038                productData, 
2039                competitorData, 
2040                coinvest, 
2041                drr
2042            );
2043            console.log('>>> bayesianPriceOptimizationWithAI FINISHED <<<');
2044            
2045            if (!optimization) {
2046                throw new Error('Ошибка при оптимизации цены');
2047            }
2048
2049            displayResults(optimization, coinvest, drr);
2050            
2051        } catch (error) {
2052            console.error('Analysis error:', error);
2053            console.error('Error message:', error.message);
2054            console.error('Error stack:', error.stack);
2055            const resultsContent = document.getElementById('results-content');
2056            resultsContent.innerHTML = `
2057                <div style="color: #fee; padding: 10px; text-align: center;">
2058                    <strong>⚠️ Ошибка:</strong><br>
2059                    ${error.message || 'Неизвестная ошибка'}
2060                </div>
2061            `;
2062            resultsDiv.style.display = 'block';
2063        } finally {
2064            loadingIndicator.style.display = 'none';
2065        }
2066    }
2067
2068    // Display optimization results
2069    function displayResults(optimization, coinvest, drr) {
2070        const resultsDiv = document.getElementById('analysis-results');
2071        const resultsContent = document.getElementById('results-content');
2072        
2073        const { optimal, alternatives, currentPrice, productData, allResults, aiReasoning, competitorData, historicalData } = optimization;
2074        
2075        const currentDailySales = historicalData.avgDailySales;
2076        
2077        // Calculate actual price from current display price using user's coinvest value
2078        const displayPriceMultiplier = (100 - coinvest) / 100;
2079        const currentActualPrice = currentPrice / displayPriceMultiplier;
2080        const currentCommission = currentActualPrice * productData.commission;
2081        const currentAdvertisingCost = currentActualPrice * (drr / 100);
2082        const currentDelivery = productData.delivery;
2083        const currentDailyProfit = Math.round((currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost) * currentDailySales * 10) / 10;
2084        const currentDailyRevenue = Math.round(currentPrice * currentDailySales * 10) / 10;
2085        const currentMargin = Math.round(((currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost) / currentActualPrice) * 100 * 10) / 10;
2086        const currentProfitPerUnit = Math.round(currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost);
2087        
2088        // Calculate percentages for current price
2089        const currentCommissionPercent = Math.round((currentCommission / currentActualPrice) * 100 * 10) / 10;
2090        const currentDeliveryPercent = Math.round((currentDelivery / currentActualPrice) * 100 * 10) / 10;
2091        const currentCostPercent = Math.round((productData.cost / currentActualPrice) * 100 * 10) / 10;
2092        const currentDrrPercent = Math.round((currentAdvertisingCost / currentActualPrice) * 100 * 10) / 10;
2093        
2094        // Calculate optimal values
2095        const optimalDailyRevenue = Math.round(optimal.price * optimal.estimatedDailySales * 10) / 10;
2096        const optimalProfitPerUnit = Math.round(optimal.actualPrice - productData.cost - optimal.commission - optimal.delivery - optimal.advertisingCost);
2097        
2098        // Calculate percentages for optimal price
2099        const optimalCommissionPercent = Math.round((optimal.commission / optimal.actualPrice) * 100 * 10) / 10;
2100        const optimalDeliveryPercent = Math.round((optimal.delivery / optimal.actualPrice) * 100 * 10) / 10;
2101        const optimalCostPercent = Math.round((productData.cost / optimal.actualPrice) * 100 * 10) / 10;
2102        const optimalDrrPercent = Math.round((optimal.advertisingCost / optimal.actualPrice) * 100 * 10) / 10;
2103        
2104        // Calculate all changes
2105        const priceChange = Math.round(((optimal.price - currentPrice) / currentPrice) * 100);
2106        const priceDiff = Math.round(optimal.price - currentPrice);
2107        const actualPriceChange = Math.round(((optimal.actualPrice - currentActualPrice) / currentActualPrice) * 100);
2108        const actualPriceDiff = Math.round(optimal.actualPrice - currentActualPrice);
2109        const revenueChange = Math.round(((optimalDailyRevenue - currentDailyRevenue) / currentDailyRevenue) * 100);
2110        const revenueDiff = Math.round(optimalDailyRevenue - currentDailyRevenue);
2111        const profitDiff = Math.round((optimal.estimatedDailyProfit - currentDailyProfit) * 10) / 10;
2112        const profitChange = currentDailyProfit !== 0 ? Math.round((profitDiff / Math.abs(currentDailyProfit)) * 100) : 0;
2113        const salesChange = Math.round(((optimal.estimatedDailySales - currentDailySales) / currentDailySales) * 100);
2114        const salesDiff = Math.round((optimal.estimatedDailySales - currentDailySales) * 10) / 10;
2115        const marginChange = Math.round((optimal.profitMargin - currentMargin) * 10) / 10;
2116        const profitPerUnitChange = currentProfitPerUnit > 0 ? Math.round(((optimalProfitPerUnit - currentProfitPerUnit) / currentProfitPerUnit) * 100) : 0;
2117        const profitPerUnitDiff = optimalProfitPerUnit - currentProfitPerUnit;
2118        
2119        // Calculate percentage changes for costs
2120        const commissionPercentChange = Math.round((optimalCommissionPercent - currentCommissionPercent) * 10) / 10;
2121        const deliveryPercentChange = Math.round((optimalDeliveryPercent - currentDeliveryPercent) * 10) / 10;
2122        const costPercentChange = Math.round((optimalCostPercent - currentCostPercent) * 10) / 10;
2123        const drrPercentChange = Math.round((optimalDrrPercent - currentDrrPercent) * 10) / 10;
2124        
2125        // Format AI reasoning with line breaks
2126        const formattedReasoning = aiReasoning
2127            .replace(/\. /g, '.<br>• ')
2128            .replace(/^/, '• ');
2129        
2130        // Determine elasticity reliability color and text
2131        let reliabilityColor = '#ef4444'; // red for bad
2132        let reliabilityText = 'Плохо';
2133        let reliabilityIcon = '⚠️';
2134        
2135        if (optimization.elasticityReliability === 'good') {
2136            reliabilityColor = '#10b981'; // green
2137            reliabilityText = 'Хорошо';
2138            reliabilityIcon = '✅';
2139        } else if (optimization.elasticityReliability === 'satisfactory') {
2140            reliabilityColor = '#f59e0b'; // orange
2141            reliabilityText = 'Удовлетворительно';
2142            reliabilityIcon = '⚡';
2143        }
2144        
2145        let html = `
2146            <div style="background: rgba(59, 130, 246, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #3b82f6;">
2147                <div style="font-size: 13px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">📊 Эластичность спроса:</div>
2148                <div style="font-size: 14px; line-height: 1.6; opacity: 0.95;">
2149                    <div style="margin-bottom: 4px;">
2150                        <strong>Коэффициент:</strong> ${optimization.aiDemandElasticity.toFixed(4)} 
2151                        <span style="font-size: 13px; opacity: 0.8;">(при изменении цены на 1%, продажи изменятся на ${(optimization.aiDemandElasticity * 100).toFixed(1)}%)</span>
2152                    </div>
2153                    <div style="margin-bottom: 4px;">
2154                        <strong>Достоверность:</strong> 
2155                        <span style="color: ${reliabilityColor}; font-weight: 600;">${reliabilityIcon} ${reliabilityText}</span>
2156                    </div>
2157                    <div style="font-size: 12px; opacity: 0.8;">
2158                        R² = ${optimization.elasticityR2.toFixed(4)}${optimization.elasticityUniquePrices} уникальных цен • ${optimization.elasticityDaysUsed} дней данных
2159                    </div>
2160                </div>
2161            </div>
2162            
2163            <div style="background: rgba(16, 185, 129, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #10b981;">
2164                <div style="font-size: 13px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">🤖 Рекомендация AI:</div>
2165                <div style="font-size: 14px; line-height: 1.6; opacity: 0.95;">${formattedReasoning}</div>
2166            </div>
2167        `;
2168        
2169        if (competitorData && competitorData.length > 0) {
2170            // Calculate total revenue for percentage
2171            const totalRevenue = competitorData.reduce((sum, c) => sum + c.revenue30days, 0);
2172            
2173            html += `
2174            <div style="background: rgba(139, 92, 246, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #8b5cf6;">
2175                <div style="font-size: 13px; font-weight: 600; margin-bottom: 8px; opacity: 0.9;">
2176                    🏪 Конкуренты (${competitorData.length} шт):
2177                </div>
2178                <div style="overflow-x: auto;">
2179                    <table style="width: 100%; border-collapse: collapse; font-size: 12px;">
2180                        <thead>
2181                            <tr style="border-bottom: 1px solid rgba(255,255,255,0.3);">
2182                                <th style="text-align: left; padding: 6px; opacity: 0.9;">#</th>
2183                                <th style="text-align: left; padding: 6px; opacity: 0.9;">Бренд</th>
2184                                <th style="text-align: right; padding: 6px; opacity: 0.9;">Цена</th>
2185                                <th style="text-align: right; padding: 6px; opacity: 0.9;">Продажи</th>
2186                                <th style="text-align: right; padding: 6px; opacity: 0.9;">Выручка</th>
2187                                <th style="text-align: right; padding: 6px; opacity: 0.9;">% выручки</th>
2188                            </tr>
2189                        </thead>
2190                        <tbody>
2191            `;
2192            
2193            competitorData.slice(0, 10).forEach((comp, index) => {
2194                const competitorUrl = comp.sku ? `https://www.ozon.ru/product/${comp.sku}/` : '#';
2195                const salesInfo = comp.sales30days ? `${comp.sales30days} шт` : 'н/д';
2196                const revenueInfo = comp.revenue30days ? `${comp.revenue30days.toLocaleString()}` : 'н/д';
2197                const revenuePercent = totalRevenue > 0 ? ((comp.revenue30days / totalRevenue) * 100).toFixed(1) : '0.0';
2198                
2199                html += `
2200                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2201                        <td style="padding: 8px 6px; opacity: 0.8;">${index + 1}</td>
2202                        <td style="padding: 8px 6px;">
2203                            <a href="${competitorUrl}" target="_blank" style="color: white; text-decoration: none; opacity: 0.9;">
2204                                ${comp.brand || 'N/A'}
2205                            </a>
2206                        </td>
2207                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${comp.price.toLocaleString()} ₽</td>
2208                        <td style="padding: 8px 6px; text-align: right;">${salesInfo}</td>
2209                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${revenueInfo}</td>
2210                        <td style="padding: 8px 6px; text-align: right; opacity: 0.9;">${revenuePercent}%</td>
2211                    </tr>
2212                `;
2213            });
2214            
2215            html += `
2216                        </tbody>
2217                    </table>
2218                </div>
2219            </div>
2220            `;
2221            
2222            // === NEW: Calculate recommended prices based on competitors ===
2223            
2224            // ШАГ 1: Средневзвешенная цена (вес 40%)
2225            let weightedSum = 0;
2226            let totalWeight = 0;
2227            competitorData.forEach((comp, index) => {
2228                const position = index + 1;
2229                const weight = position <= 5 ? comp.revenue30days * 2 : comp.revenue30days;
2230                weightedSum += comp.price * weight;
2231                totalWeight += weight;
2232            });
2233            const weightedAvgPrice = totalWeight > 0 ? Math.round(weightedSum / totalWeight) : 0;
2234            
2235            // ШАГ 2: Цена с лучшей конверсией (вес 30%)
2236            const competitorsWithConversion = competitorData.map(comp => ({
2237                ...comp,
2238                conversion: comp.sales30days > 0 ? comp.sales30days / comp.price : 0
2239            }));
2240            competitorsWithConversion.sort((a, b) => b.conversion - a.conversion);
2241            const top3Conversion = competitorsWithConversion.slice(0, 3);
2242            const bestConversionPrice = top3Conversion.length > 0 
2243                ? Math.round(top3Conversion.reduce((sum, c) => sum + c.price, 0) / top3Conversion.length)
2244                : 0;
2245            
2246            // ШАГ 3: Медианная цена топ-10 (вес 30%)
2247            const top10Prices = competitorData.slice(0, 10).map(c => c.price).sort((a, b) => a - b);
2248            let medianPrice = 0;
2249            if (top10Prices.length > 0) {
2250                const mid = Math.floor(top10Prices.length / 2);
2251                medianPrice = top10Prices.length % 2 === 0 
2252                    ? Math.round((top10Prices[mid - 1] + top10Prices[mid]) / 2)
2253                    : top10Prices[mid];
2254            }
2255            
2256            // ШАГ 3.5: Эластичность запроса (на основе данных конкурентов)
2257            let queryElasticity = -1.5; // default
2258            let queryElasticityR2 = 0;
2259            
2260            if (competitorData.length >= 5) {
2261                console.log('=== CALCULATING QUERY ELASTICITY (Cross-Sectional) ===');
2262                console.log('Using competitor data:', competitorData.map(c => `${c.brand}: ${c.price}₽, ${c.sales30days} шт/30д`));
2263                
2264                // Используем лог-линейную регрессию для конкурентов
2265                const logPrices = competitorData.map(c => Math.log(c.price));
2266                const logSales = competitorData.map(c => Math.log(c.sales30days + 1));
2267                
2268                console.log('Log prices:', logPrices.map(p => p.toFixed(4)));
2269                console.log('Log sales:', logSales.map(s => s.toFixed(4)));
2270                
2271                const n = competitorData.length;
2272                const sumX = logPrices.reduce((a, b) => a + b, 0);
2273                const sumY = logSales.reduce((a, b) => a + b, 0);
2274                const sumXY = logPrices.reduce((a, b, i) => a + b * logSales[i], 0);
2275                const sumX2 = logPrices.reduce((a, b) => a + b * b, 0);
2276                
2277                console.log(`Query elasticity regression: n=${n}, sumX=${sumX.toFixed(2)}, sumY=${sumY.toFixed(2)}, sumXY=${sumXY.toFixed(2)}, sumX2=${sumX2.toFixed(2)}`);
2278                
2279                const denominator = n * sumX2 - sumX * sumX;
2280                console.log('Denominator:', denominator.toFixed(4));
2281                
2282                if (denominator !== 0) {
2283                    const slope = (n * sumXY - sumX * sumY) / denominator;
2284                    const intercept = (sumY - slope * sumX) / n;
2285                    
2286                    console.log(`Query OLS results: slope (elasticity) = ${slope.toFixed(4)}, intercept = ${intercept.toFixed(4)}`);
2287                    
2288                    // Calculate R²
2289                    const yMean = sumY / n;
2290                    const ssTotal = logSales.reduce((s, y) => s + Math.pow(y - yMean, 2), 0);
2291                    const predicted = logPrices.map(x => slope * x + intercept);
2292                    const ssResidual = logSales.reduce((s, y, i) => s + Math.pow(y - predicted[i], 2), 0);
2293                    const r2 = ssTotal > 0 ? 1 - (ssResidual / ssTotal) : 0;
2294                    
2295                    console.log(`Query R²: ssTotal=${ssTotal.toFixed(4)}, ssResidual=${ssResidual.toFixed(4)}, R²=${r2.toFixed(4)}`);
2296                    
2297                    // Clamp to reasonable range
2298                    queryElasticity = Math.max(-3.0, Math.min(-0.3, slope));
2299                    queryElasticityR2 = r2;
2300                    
2301                    console.log('Query elasticity calculated:', queryElasticity.toFixed(4), 'R²:', r2.toFixed(4));
2302                    console.log('⚠️ NOTE: Cross-sectional elasticity may differ from time-series elasticity due to brand effects, quality differences, and search position');
2303                } else {
2304                    console.log('⚠️ Query elasticity: denominator is zero, using default -1.5');
2305                }
2306            }
2307            
2308            // ШАГ 4: Базовая оптимальная цена
2309            const baseOptimalPrice = Math.round(
2310                weightedAvgPrice * 0.4 + 
2311                bestConversionPrice * 0.3 + 
2312                medianPrice * 0.3
2313            );
2314            
2315            // ШАГ 6: Три стратегии
2316            const marketCapturePrice = Math.round(baseOptimalPrice * 0.85);
2317            const optimalStrategyPrice = baseOptimalPrice;
2318            const premiumPrice = Math.round(baseOptimalPrice * 1.15);
2319            
2320            html += `
2321            <div style="background: rgba(236, 72, 153, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #ec4899;">
2322                <div style="font-size: 13px; font-weight: 600; margin-bottom: 8px; opacity: 0.9;">
2323                    💰 Рекомендованные цены для запроса
2324                </div>
2325                
2326                <div style="margin-bottom: 10px; padding: 8px; background: rgba(255,255,255,0.1); border-radius: 6px;">
2327                    <div style="font-size: 12px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">📈 Базовые метрики:</div>
2328                    <div style="font-size: 13px; line-height: 1.8;">
2329                        <div>• <strong>Средневзвешенная цена:</strong> ${weightedAvgPrice} ₽ <span style="opacity: 0.7;">(вес 40%)</span></div>
2330                        <div>• <strong>Цена с лучшей конверсией:</strong> ${bestConversionPrice} ₽ <span style="opacity: 0.7;">(вес 30%)</span></div>
2331                        <div>• <strong>Медианная цена топ-10:</strong> ${medianPrice} ₽ <span style="opacity: 0.7;">(вес 30%)</span></div>
2332                        <div>• <strong>Эластичность запроса:</strong> ${queryElasticity.toFixed(4)} <span style="opacity: 0.7;">(R² = ${queryElasticityR2.toFixed(3)}, ${competitorData.length} конкурентов)</span></div>
2333                    </div>
2334                </div>
2335                
2336                <div style="font-size: 12px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">🎯 Стратегии ценообразования:</div>
2337                <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;">
2338                    <div style="background: rgba(239, 68, 68, 0.3); padding: 8px; border-radius: 6px; text-align: center;">
2339                        <div style="font-size: 11px; opacity: 0.8; margin-bottom: 4px;">🔥 Захват рынка</div>
2340                        <div style="font-size: 18px; font-weight: 700;">${marketCapturePrice} ₽</div>
2341                        <div style="font-size: 10px; opacity: 0.7; margin-top: 2px;">-15% от базовой</div>
2342                    </div>
2343                    <div style="background: rgba(16, 185, 129, 0.3); padding: 8px; border-radius: 6px; text-align: center;">
2344                        <div style="font-size: 11px; opacity: 0.8; margin-bottom: 4px;">⚖️ Оптимальная</div>
2345                        <div style="font-size: 18px; font-weight: 700;">${optimalStrategyPrice} ₽</div>
2346                        <div style="font-size: 10px; opacity: 0.7; margin-top: 2px;">базовая цена</div>
2347                    </div>
2348                    <div style="background: rgba(245, 158, 11, 0.3); padding: 8px; border-radius: 6px; text-align: center;">
2349                        <div style="font-size: 11px; opacity: 0.8; margin-bottom: 4px;">👑 Премиум</div>
2350                        <div style="font-size: 18px; font-weight: 700;">${premiumPrice} ₽</div>
2351                        <div style="font-size: 10px; opacity: 0.7; margin-top: 2px;">+25% от базовой</div>
2352                    </div>
2353                </div>
2354            `;
2355        }
2356
2357        html += `
2358            <div style="background: #10b981; padding: 5px 10px; border-radius: 6px; font-size: 13px; font-weight: 600; display: inline-block; margin-bottom: 10px;">
2359                ✨ ОПТИМАЛЬНАЯ ЦЕНА
2360            </div>
2361            
2362            <table style="width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 14px;">
2363                <thead>
2364                    <tr style="border-bottom: 2px solid rgba(255,255,255,0.3);">
2365                        <th style="text-align: left; padding: 6px; font-size: 14px; opacity: 0.9;">Показатель</th>
2366                        <th style="text-align: right; padding: 6px; font-size: 14px; opacity: 0.9;">Текущая</th>
2367                        <th style="text-align: right; padding: 6px; font-size: 14px; opacity: 0.9;">Рекомендуемая</th>
2368                        <th style="text-align: right; padding: 6px; font-size: 14px; opacity: 0.9;">Δ</th>
2369                    </tr>
2370                </thead>
2371                <tbody>
2372                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2373                        <td style="padding: 8px 6px; font-size: 14px;">Цена реализации</td>
2374                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentPrice} ₽</td>
2375                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2376                            ${optimal.price}2377                            <span style="color: ${priceChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2378                                (${priceChange >= 0 ? '+' : ''}${priceChange}%)
2379                            </span>
2380                        </td>
2381                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${priceDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2382                            ${priceDiff >= 0 ? '+' : ''}${priceDiff}2383                        </td>
2384                    </tr>
2385                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2386                        <td style="padding: 8px 6px; font-size: 14px;">Фактическая цена</td>
2387                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${Math.round(currentActualPrice)} ₽</td>
2388                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2389                            ${Math.round(optimal.actualPrice)}2390                            <span style="color: ${actualPriceChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2391                                (${actualPriceChange >= 0 ? '+' : ''}${actualPriceChange}%)
2392                            </span>
2393                        </td>
2394                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${actualPriceDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2395                            ${actualPriceDiff >= 0 ? '+' : ''}${actualPriceDiff}2396                        </td>
2397                    </tr>
2398                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2399                        <td style="padding: 8px 6px; font-size: 14px;">Прибыль/день</td>
2400                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDailyProfit} ₽</td>
2401                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2402                            ${optimal.estimatedDailyProfit}2403                            <span style="color: ${profitChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2404                                (${profitChange >= 0 ? '+' : ''}${profitChange}%)
2405                            </span>
2406                        </td>
2407                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${profitDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2408                            ${profitDiff >= 0 ? '+' : ''}${profitDiff}2409                        </td>
2410                    </tr>
2411                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2412                        <td style="padding: 8px 6px; font-size: 14px;">Выручка/день</td>
2413                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDailyRevenue} ₽</td>
2414                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2415                            ${optimalDailyRevenue}2416                            <span style="color: ${revenueChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2417                                (${revenueChange >= 0 ? '+' : ''}${revenueChange}%)
2418                            </span>
2419                        </td>
2420                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${revenueDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2421                            ${revenueDiff >= 0 ? '+' : ''}${revenueDiff}2422                        </td>
2423                    </tr>
2424                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2425                        <td style="padding: 8px 6px; font-size: 14px;">Продажи/день</td>
2426                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDailySales.toFixed(1)} шт</td>
2427                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2428                            ${optimal.estimatedDailySales} шт 
2429                            <span style="color: ${salesChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2430                                (${salesChange >= 0 ? '+' : ''}${salesChange}%)
2431                            </span>
2432                        </td>
2433                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${salesDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2434                            ${salesDiff >= 0 ? '+' : ''}${salesDiff} шт
2435                        </td>
2436                    </tr>
2437                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2438                        <td style="padding: 8px 6px; font-size: 14px;">Маржа %</td>
2439                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentMargin}%</td>
2440                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2441                            ${optimal.profitMargin}% 
2442                            <span style="color: ${marginChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2443                                (${marginChange >= 0 ? '+' : ''}${marginChange}%)
2444                            </span>
2445                        </td>
2446                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${marginChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2447                            ${marginChange >= 0 ? '+' : ''}${marginChange}%
2448                        </td>
2449                    </tr>
2450                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2451                        <td style="padding: 8px 6px; font-size: 14px;">Прибыль/шт</td>
2452                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentProfitPerUnit} ₽</td>
2453                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2454                            ${optimalProfitPerUnit}2455                            <span style="color: ${profitPerUnitChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2456                                (${profitPerUnitChange >= 0 ? '+' : ''}${profitPerUnitChange}%)
2457                            </span>
2458                        </td>
2459                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${profitPerUnitDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2460                            ${profitPerUnitDiff >= 0 ? '+' : ''}${profitPerUnitDiff}2461                        </td>
2462                    </tr>
2463                    <tr>
2464                        <td style="padding: 8px 6px; font-size: 14px;">Комиссия %</td>
2465                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentCommissionPercent}%</td>
2466                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2467                            ${optimalCommissionPercent}%
2468                            <span style="color: ${commissionPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2469                                (${commissionPercentChange >= 0 ? '+' : ''}${commissionPercentChange}%)
2470                            </span>
2471                        </td>
2472                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${commissionPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2473                            ${commissionPercentChange >= 0 ? '+' : ''}${commissionPercentChange}%
2474                        </td>
2475                    </tr>
2476                    <tr>
2477                        <td style="padding: 8px 6px; font-size: 14px;">Доставка %</td>
2478                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDeliveryPercent}%</td>
2479                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2480                            ${optimalDeliveryPercent}%
2481                            <span style="color: ${deliveryPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2482                                (${deliveryPercentChange >= 0 ? '+' : ''}${deliveryPercentChange}%)
2483                            </span>
2484                        </td>
2485                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${deliveryPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2486                            ${deliveryPercentChange >= 0 ? '+' : ''}${deliveryPercentChange}%
2487                        </td>
2488                    </tr>
2489                    <tr>
2490                        <td style="padding: 8px 6px; font-size: 14px;">Себестоимость %</td>
2491                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentCostPercent}%</td>
2492                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2493                            ${optimalCostPercent}%
2494                            <span style="color: ${costPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2495                                (${costPercentChange >= 0 ? '+' : ''}${costPercentChange}%)
2496                            </span>
2497                        </td>
2498                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${costPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2499                            ${costPercentChange >= 0 ? '+' : ''}${costPercentChange}%
2500                        </td>
2501                    </tr>
2502                    <tr>
2503                        <td style="padding: 8px 6px; font-size: 14px;">ДРР %</td>
2504                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDrrPercent}%</td>
2505                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2506                            ${optimalDrrPercent}%
2507                            <span style="color: ${drrPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2508                                (${drrPercentChange >= 0 ? '+' : ''}${drrPercentChange}%)
2509                            </span>
2510                        </td>
2511                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${drrPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2512                            ${drrPercentChange >= 0 ? '+' : ''}${drrPercentChange}%
2513                        </td>
2514                    </tr>
2515                </tbody>
2516            </table>
2517        `;
2518
2519        if (alternatives && alternatives.length > 0) {
2520            html += `
2521                <div style="margin-top: 12px; padding: 8px; background: rgba(255,255,255,0.1); border-radius: 6px; font-size: 12px; opacity: 0.8;">
2522                    💡 Анализ: ${allResults.length} вариантов цен. Уверенность: ${Math.round(optimal.confidence * 100)}%
2523                </div>
2524            `;
2525        }
2526
2527        resultsContent.innerHTML = html;
2528        resultsDiv.style.display = 'block';
2529        
2530        setTimeout(() => createPriceChart(optimization), 100);
2531    }
2532
2533    // Create price analysis chart
2534    function createPriceChart(optimization) {
2535        const oldChart = document.getElementById('price-analysis-chart');
2536        if (oldChart) {
2537            oldChart.parentElement.remove();
2538        }
2539        
2540        const canvas = document.createElement('canvas');
2541        canvas.id = 'price-analysis-chart';
2542        canvas.style.cssText = 'width: 100% !important; height: 250px !important;';
2543        
2544        const chartContainer = document.createElement('div');
2545        chartContainer.style.cssText = 'margin-top: 12px; padding: 12px; background: rgba(255,255,255,0.1); border-radius: 8px; max-width: 600px; box-sizing: border-box;';
2546        chartContainer.innerHTML = `
2547            <div style="font-size: 14px; margin-bottom: 8px; opacity: 0.9; font-weight: 600;">
2548                📈 График зависимости от цены
2549            </div>
2550        `;
2551        chartContainer.appendChild(canvas);
2552        
2553        const resultsContent = document.getElementById('results-content');
2554        resultsContent.appendChild(chartContainer);
2555        
2556        const sortedResults = [...optimization.allResults].sort((a, b) => a.price - b.price);
2557        const prices = sortedResults.map(r => r.price);
2558        const sales = sortedResults.map(r => r.estimatedDailySales);
2559        const revenue = sortedResults.map(r => Math.round(r.price * r.estimatedDailySales));
2560        const profit = sortedResults.map(r => r.estimatedDailyProfit);
2561        
2562        const ctx = canvas.getContext('2d');
2563        window.priceAnalysisChart = new Chart(ctx, {
2564            type: 'line',
2565            data: {
2566                labels: prices,
2567                datasets: [
2568                    {
2569                        label: 'Продажи (шт/д)',
2570                        data: sales,
2571                        borderColor: '#10b981',
2572                        backgroundColor: 'rgba(16, 185, 129, 0.1)',
2573                        yAxisID: 'y',
2574                        tension: 0.4,
2575                        borderWidth: 2
2576                    },
2577                    {
2578                        label: 'Выручка (₽/д)',
2579                        data: revenue,
2580                        borderColor: '#f59e0b',
2581                        backgroundColor: 'rgba(245, 158, 11, 0.1)',
2582                        yAxisID: 'y1',
2583                        tension: 0.4,
2584                        borderWidth: 2
2585                    },
2586                    {
2587                        label: 'Прибыль (₽/д)',
2588                        data: profit,
2589                        borderColor: '#ef4444',
2590                        backgroundColor: 'rgba(239, 68, 68, 0.1)',
2591                        yAxisID: 'y1',
2592                        tension: 0.4,
2593                        borderWidth: 3
2594                    }
2595                ]
2596            },
2597            options: {
2598                responsive: true,
2599                maintainAspectRatio: true,
2600                aspectRatio: 2.2,
2601                interaction: {
2602                    mode: 'index',
2603                    intersect: false,
2604                },
2605                plugins: {
2606                    legend: {
2607                        position: 'top',
2608                        labels: {
2609                            usePointStyle: true,
2610                            padding: 12,
2611                            font: { size: 12 },
2612                            color: 'white',
2613                            boxWidth: 8,
2614                            boxHeight: 8
2615                        }
2616                    },
2617                    tooltip: {
2618                        backgroundColor: 'rgba(0, 0, 0, 0.8)',
2619                        padding: 10,
2620                        titleFont: { size: 13 },
2621                        bodyFont: { size: 12 },
2622                        callbacks: {
2623                            title: function(context) {
2624                                return 'Цена: ' + context[0].label + ' ₽';
2625                            },
2626                            label: function(context) {
2627                                let label = context.dataset.label || '';
2628                                if (label) {
2629                                    label += ': ';
2630                                }
2631                                if (context.parsed.y !== null) {
2632                                    if (label.includes('шт')) {
2633                                        label += context.parsed.y.toFixed(1);
2634                                    } else {
2635                                        label += Math.round(context.parsed.y);
2636                                    }
2637                                }
2638                                return label;
2639                            }
2640                        }
2641                    }
2642                },
2643                scales: {
2644                    x: {
2645                        title: {
2646                            display: true,
2647                            text: 'Цена (₽)',
2648                            font: { size: 12, weight: 'bold' },
2649                            color: 'white'
2650                        },
2651                        ticks: {
2652                            maxTicksLimit: 8,
2653                            font: { size: 11 },
2654                            color: 'rgba(255, 255, 255, 0.8)'
2655                        },
2656                        grid: {
2657                            color: 'rgba(255, 255, 255, 0.1)'
2658                        }
2659                    },
2660                    y: {
2661                        type: 'linear',
2662                        display: true,
2663                        position: 'left',
2664                        title: {
2665                            display: true,
2666                            text: 'Продажи',
2667                            color: '#10b981',
2668                            font: { size: 12 }
2669                        },
2670                        ticks: {
2671                            font: { size: 11 },
2672                            color: 'rgba(255, 255, 255, 0.8)'
2673                        },
2674                        grid: {
2675                            color: 'rgba(255, 255, 255, 0.1)'
2676                        }
2677                    },
2678                    y1: {
2679                        type: 'linear',
2680                        display: true,
2681                        position: 'right',
2682                        title: {
2683                            display: true,
2684                            text: 'Выручка/Прибыль',
2685                            color: '#f59e0b',
2686                            font: { size: 12 }
2687                        },
2688                        grid: {
2689                            drawOnChartArea: false,
2690                        },
2691                        ticks: {
2692                            font: { size: 11 },
2693                            color: 'rgba(255, 255, 255, 0.8)'
2694                        }
2695                    }
2696                }
2697            }
2698        });
2699        
2700        console.log('График создан успешно');
2701    }
2702
2703    // Wait for MP Stats widget to load
2704    function waitForMPStats() {
2705        console.log('Waiting for MP Stats widget...');
2706        
2707        let checkCount = 0;
2708        const maxChecks = 30;
2709        
2710        const checkInterval = setInterval(() => {
2711            checkCount++;
2712            console.log(`Check ${checkCount}/${maxChecks} for MP Stats widget...`);
2713            
2714            const mpsWidget = document.querySelector('.mps-sidebar');
2715            
2716            if (mpsWidget) {
2717                console.log('MP Stats widget found, creating analysis widget...');
2718                clearInterval(checkInterval);
2719                setTimeout(() => {
2720                    console.log('Creating analysis widget now...');
2721                    createAnalysisWidget();
2722                }, 2000);
2723            } else if (checkCount >= maxChecks) {
2724                clearInterval(checkInterval);
2725                console.log('Stopped waiting for MP Stats widget - timeout reached');
2726            }
2727        }, 1000);
2728    }
2729
2730    // Initialize
2731    function init() {
2732        console.log('OZON Price Optimizer initialized (v2.0.1)');
2733        console.log('Current URL:', window.location.href);
2734        
2735        // Check if we're on a search page and need to extract competitors
2736        if (window.location.href.includes('/search/') || window.location.href.includes('/category/')) {
2737            console.log('Search/category page detected, checking for competitor extraction...');
2738            extractCompetitorsInSearchPage();
2739            return;
2740        }
2741        
2742        const productId = getProductId();
2743        if (!productId) {
2744            console.log('Not a product page, skipping...');
2745            return;
2746        }
2747
2748        console.log('Product page detected, waiting for MP Stats widget...');
2749        
2750        if (document.readyState === 'loading') {
2751            document.addEventListener('DOMContentLoaded', waitForMPStats);
2752        } else {
2753            waitForMPStats();
2754        }
2755    }
2756
2757    init();
2758})();