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

137.1 KB

Version

2.1.46

Created

Dec 17, 2025

Updated

about 2 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.46
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 (v2.0.1) <<<');
547        
548        try {
549            const dailyData = [];
550            const svgs = widget.querySelectorAll('svg.apexcharts-svg');
551            console.log('Found ApexCharts SVG elements:', svgs.length);
552            
553            if (svgs.length === 0) {
554                console.log('No SVG charts found');
555                return dailyData;
556            }
557            
558            const salesSvg = svgs[0];
559            console.log('Analyzing sales chart (SVG 0)...');
560            
561            const bars = salesSvg.querySelectorAll('path.apexcharts-bar-area');
562            console.log(`Found ${bars.length} bar elements`);
563            
564            if (bars.length === 0) {
565                console.log('No bars found in sales chart');
566                return dailyData;
567            }
568            
569            console.log('Starting tooltip extraction...');
570            
571            const indices = [];
572            for (let i = 1; i < bars.length; i++) {
573                indices.push(i);
574            }
575            indices.push(0);
576            
577            for (const index of indices) {
578                const bar = bars[index];
579                const rect = bar.getBoundingClientRect();
580                const centerX = rect.left + rect.width / 2;
581                const centerY = rect.top + rect.height / 2;
582                
583                console.log(`Day ${index + 1}: rect:`, { left: rect.left, top: rect.top, width: rect.width, height: rect.height });
584                
585                bar.dispatchEvent(new MouseEvent('mousemove', { 
586                    bubbles: true, 
587                    cancelable: true, 
588                    view: window,
589                    clientX: centerX,
590                    clientY: centerY
591                }));
592                
593                const waitTime = index <= 2 ? 800 : 200;
594                await new Promise(resolve => setTimeout(resolve, waitTime));
595                
596                let tooltip = document.querySelector('.chart-custom-tooltip');
597                let retries = 0;
598                const maxRetries = index === 0 ? 8 : 5;
599                
600                while (!tooltip && retries < maxRetries) {
601                    console.log(`Day ${index + 1}: Tooltip not found, retry ${retries + 1}/${maxRetries}`);
602                    
603                    bar.dispatchEvent(new MouseEvent('mousemove', { 
604                        bubbles: true, 
605                        cancelable: true, 
606                        view: window,
607                        clientX: centerX,
608                        clientY: centerY
609                    }));
610                    
611                    await new Promise(resolve => setTimeout(resolve, 400));
612                    tooltip = document.querySelector('.chart-custom-tooltip');
613                    retries++;
614                }
615                
616                if (!tooltip) {
617                    console.log(`Day ${index + 1}: Tooltip not found after ${maxRetries} retries, skipping`);
618                    continue;
619                }
620                
621                const tooltipText = tooltip.textContent;
622                console.log(`Day ${index + 1}: Tooltip text:`, tooltipText);
623                
624                const salesMatch = tooltipText.match(/Продажи:\s*(\d+)\s*шт/);
625                const sales = salesMatch ? parseInt(salesMatch[1]) : null;
626                
627                const priceMatch = tooltipText.match(/Цена:\s*(\d+)\s*₽/);
628                const price = priceMatch ? parseInt(priceMatch[1]) : null;
629                
630                if (sales !== null && price !== null && sales > 0 && price > 0) {
631                    dailyData.push({
632                        day: index + 1,
633                        sales: sales,
634                        price: price
635                    });
636                } else {
637                    console.log(`Day ${index + 1}: Invalid data - sales: ${sales}, price: ${price}`);
638                }
639            }
640            
641            console.log(`Total extracted daily data points: ${dailyData.length}`);
642            console.log('Sample data - First 5 days:', dailyData.slice(0, 5));
643            console.log('Sample data - Last 5 days:', dailyData.slice(-5));
644            return dailyData;
645            
646        } catch (error) {
647            console.error('Error extracting daily data:', error);
648            return [];
649        }
650    }
651
652    // Extract stock data from MP Stats stock chart
653    async function extractStockData(widget) {
654        console.log('Extracting stock data from MP Stats...');
655        
656        if (!widget) {
657            console.error('Widget not provided to extractStockData');
658            return null;
659        }
660        
661        const svgs = widget.querySelectorAll('svg.apexcharts-svg');
662        console.log(`Found ${svgs.length} SVG charts for stock data`);
663        
664        if (!svgs || svgs.length < 4) {
665            console.error(`Stock chart SVG not found - only ${svgs ? svgs.length : 0} charts available, need at least 4`);
666            return null;
667        }
668        
669        const stockSvg = svgs[3];
670        console.log('Analyzing stock chart (SVG 3)...');
671        
672        const stockBars = stockSvg.querySelectorAll('path.apexcharts-bar-area');
673        console.log(`Found ${stockBars.length} stock bars in fourth chart`);
674        
675        if (!stockBars || stockBars.length === 0) {
676            console.error('No stock bars found in fourth chart');
677            return null;
678        }
679
680        const stockPoints = [];
681        console.log('Starting stock tooltip extraction...');
682        
683        const indices = [];
684        for (let i = 1; i < stockBars.length; i++) {
685            indices.push(i);
686        }
687        indices.push(0);
688        
689        for (const index of indices) {
690            const bar = stockBars[index];
691            const rect = bar.getBoundingClientRect();
692            const centerX = rect.left + rect.width / 2;
693            const centerY = rect.top + rect.height / 2;
694            
695            console.log(`Stock Day ${index + 1}: rect:`, { left: rect.left, top: rect.top, width: rect.width, height: rect.height });
696            
697            bar.dispatchEvent(new MouseEvent('mousemove', { 
698                bubbles: true, 
699                cancelable: true, 
700                view: window,
701                clientX: centerX,
702                clientY: centerY
703            }));
704            
705            const waitTime = index <= 2 ? 800 : 200;
706            await new Promise(resolve => setTimeout(resolve, waitTime));
707            
708            let tooltip = document.querySelector('.chart-custom-tooltip');
709            let retries = 0;
710            const maxRetries = index === 0 ? 8 : 5;
711            
712            while (!tooltip && retries < maxRetries) {
713                console.log(`Stock Day ${index + 1}: Tooltip not found, retry ${retries + 1}/${maxRetries}`);
714                
715                bar.dispatchEvent(new MouseEvent('mousemove', { 
716                    bubbles: true, 
717                    cancelable: true, 
718                    view: window,
719                    clientX: centerX,
720                    clientY: centerY
721                }));
722                
723                await new Promise(resolve => setTimeout(resolve, 400));
724                tooltip = document.querySelector('.chart-custom-tooltip');
725                retries++;
726            }
727            
728            if (!tooltip) {
729                console.log(`Stock Day ${index + 1}: Tooltip not found after ${maxRetries} retries, skipping`);
730                continue;
731            }
732            
733            const tooltipText = tooltip.textContent;
734            console.log(`Stock Day ${index + 1}: Tooltip text:`, tooltipText);
735            
736            const stockMatch = tooltipText.match(/Остаток:\s*(\d+)\s*шт/) || tooltipText.match(/(\d+)\s*шт/);
737            const stock = stockMatch ? parseInt(stockMatch[1]) : null;
738            
739            if (stock !== null && stock >= 0) {
740                stockPoints.push({
741                    day: index + 1,
742                    stock: stock
743                });
744                console.log(`Stock Day ${index + 1}: Extracted stock: ${stock}`);
745            } else {
746                console.log(`Stock Day ${index + 1}: Invalid stock data - stock: ${stock}`);
747            }
748        }
749
750        console.log(`Extracted ${stockPoints.length} days of stock data from chart`);
751        console.log('Stock data sample - First 5 days:', stockPoints.slice(0, 5));
752        console.log('Stock data sample - Last 5 days:', stockPoints.slice(-5));
753        return stockPoints;
754    }
755
756    // NEW: Extract competitors from search query
757    async function extractCompetitorsFromSearch(keyQuery) {
758        console.log('=== START extractCompetitorsFromSearch ===');
759        console.log('Key query:', keyQuery);
760        
761        try {
762            // Encode query for URL
763            const encodedQuery = encodeURIComponent(keyQuery);
764            const searchUrl = `https://www.ozon.ru/search/?text=${encodedQuery}&from_global=true`;
765            
766            console.log('Opening search URL in new tab:', searchUrl);
767            console.log('⚠️ ВАЖНО: Новая вкладка откроется для сбора данных о конкурентах. Пожалуйста, не закрывайте её - она закроется автоматически.');
768            
769            // Open search page in new tab (in foreground so user can see it)
770            await GM.openInTab(searchUrl, true);
771            
772            // Wait for new tab to load and process
773            console.log('Waiting for search page to load...');
774            
775            // The new tab will handle extraction and save to storage
776            // This function just initiates the process
777            return null;
778            
779        } catch (error) {
780            console.error('Error in extractCompetitorsFromSearch:', error);
781            return null;
782        }
783    }
784
785    // NEW: Extract competitors in search page context
786    async function extractCompetitorsInSearchPage() {
787        console.log('=== extractCompetitorsInSearchPage CALLED ===');
788        
789        // Check if we're on a search or category page
790        if (!window.location.href.includes('/search/') && !window.location.href.includes('/category/')) {
791            console.log('Not on search/category page, skipping competitor extraction');
792            return;
793        }
794        
795        // Check if we have a pending analysis state (meaning we came from product page)
796        const stateJson = await GM.getValue('analysis_state', null);
797        if (!stateJson) {
798            console.log('No analysis state found, not extracting competitors');
799            return;
800        }
801        
802        const state = JSON.parse(stateJson);
803        
804        // Check if state is recent (within 2 minutes)
805        if (Date.now() - state.timestamp > 120000) {
806            console.log('Analysis state is too old, ignoring');
807            await GM.deleteValue('analysis_state');
808            return;
809        }
810        
811        console.log('Found analysis state, will extract competitors from this search page');
812        
813        // Wait for MPStats widget to load
814        console.log('Waiting for MPStats widget to load...');
815        let mpstatsWidget = null;
816        let attempts = 0;
817        const maxAttempts = 30;
818        
819        while (attempts < maxAttempts && !mpstatsWidget) {
820            await new Promise(resolve => setTimeout(resolve, 1000));
821            mpstatsWidget = document.getElementById('mpstat-ozone-search-result');
822            attempts++;
823            console.log(`Attempt ${attempts}/${maxAttempts} to find MPStats widget...`);
824        }
825        
826        if (!mpstatsWidget) {
827            console.error('MPStats widget not found in search results after 30 seconds');
828            // Mark as failed and close tab
829            await GM.setValue('competitors_extracted', 'failed');
830            window.close();
831            return;
832        }
833        
834        console.log('MPStats widget found, waiting for data to load...');
835        
836        // Wait for table rows to appear
837        let rows = [];
838        attempts = 0;
839        
840        while (attempts < 20 && rows.length === 0) {
841            await new Promise(resolve => setTimeout(resolve, 1000));
842            rows = mpstatsWidget.querySelectorAll('tbody tr');
843            attempts++;
844            console.log(`Attempt ${attempts}/20: Found ${rows.length} rows`);
845        }
846        
847        if (rows.length === 0) {
848            console.error('No rows found in MPStats table after waiting');
849            await GM.setValue('competitors_extracted', 'failed');
850            window.close();
851            return;
852        }
853        
854        console.log(`Found ${rows.length} rows in MPStats table, extracting competitor data...`);
855        
856        const competitors = [];
857        
858        for (let i = 0; i < rows.length; i++) {
859            const row = rows[i];
860            
861            try {
862                // Extract SKU from the third column
863                const skuCell = row.querySelectorAll('td')[2];
864                if (!skuCell) continue;
865                
866                const skuText = skuCell.textContent.trim();
867                const sku = skuText.match(/\d+/) ? skuText.match(/\d+/)[0] : null;
868                
869                if (!sku) continue;
870                
871                // Extract brand from the fourth column
872                const brandCell = row.querySelectorAll('td')[3];
873                if (!brandCell) continue;
874                
875                const brand = brandCell.textContent.trim();
876                
877                if (!brand || brand.length < 2) continue;
878                
879                // Extract price from the fifth column
880                const priceCell = row.querySelectorAll('td')[4];
881                if (!priceCell) continue;
882                
883                const priceText = priceCell.textContent.trim();
884                const priceMatch = priceText.match(/(\d[\d\s]*)\s*₽/);
885                if (!priceMatch) continue;
886                
887                const price = parseInt(priceMatch[1].replace(/\s/g, ''));
888                if (isNaN(price) || price < 100 || price > 100000) continue;
889                
890                // Extract sales from the sixth column (orders per month)
891                const salesCell = row.querySelectorAll('td')[5];
892                if (!salesCell) continue;
893                
894                const salesText = salesCell.textContent.trim();
895                const sales = parseInt(salesText.replace(/\s/g, ''));
896                if (isNaN(sales)) continue;
897                
898                // Calculate revenue
899                const revenue = price * sales;
900                
901                if (revenue > 0) {
902                    competitors.push({
903                        brand: brand,
904                        sku: sku,
905                        price: price,
906                        sales30days: sales,
907                        revenue30days: revenue
908                    });
909                    
910                    console.log(`Competitor: ${brand} - Price: ${price}₽, Sales: ${sales}, Revenue: ${revenue}`);
911                }
912                
913            } catch (error) {
914                console.error(`Error extracting competitor from row ${i}:`, error);
915            }
916        }
917        
918        // Sort by revenue (descending)
919        competitors.sort((a, b) => b.revenue30days - a.revenue30days);
920        
921        console.log(`Extracted ${competitors.length} competitors from search`);
922        console.log('>>> COMPETITOR PRICES EXTRACTED <<<');
923        console.log('Competitor count:', competitors.length);
924        if (competitors.length > 0) {
925            const prices = competitors.map(c => c.price);
926            const minCompPrice = Math.min(...prices);
927            const maxCompPrice = Math.max(...prices);
928            const avgCompPrice = Math.round(prices.reduce((a, b) => a + b, 0) / prices.length);
929            console.log('Price range:', minCompPrice, '-', maxCompPrice, '₽');
930            console.log('Average price:', avgCompPrice, '₽');
931            console.log('All competitor prices:', prices);
932            console.log('Top 5 competitors by revenue:', competitors.slice(0, 5).map(c => `${c.brand}: ${c.price}₽, ${c.sales30days} шт, ${c.revenue30days}`));
933        }
934        
935        // Save competitors to storage
936        await GM.setValue('temp_competitors', JSON.stringify(competitors));
937        console.log('Competitors saved to storage');
938        
939        // Mark that extraction is complete
940        await GM.setValue('competitors_extracted', 'true');
941        
942        // Close the tab after successful extraction
943        console.log('Closing competitor search tab...');
944        setTimeout(() => {
945            window.close();
946        }, 1000);
947    }
948
949    // Extract summary data from MP Stats widget
950    async function extractMPStatsData() {
951        console.log('Extracting MP Stats summary data...');
952        
953        const widget = document.querySelector('.mps-sidebar');
954        if (!widget) {
955            console.error('MP Stats widget not found');
956            return null;
957        }
958
959        const revenueText = widget.textContent.match(/Выручка за 30 суток\s*([\d\s]+)/);
960        const salesText = widget.textContent.match(/Продаж за 30 суток\s*([\d\s]+)/);
961        const currentStockText = widget.textContent.match(/Текущий остаток\s*([\d\s]+)/);
962        
963        if (revenueText && salesText) {
964            const revenue = parseInt(revenueText[1].replace(/\s/g, ''));
965            const sales = parseInt(salesText[1].replace(/\s/g, ''));
966            
967            let avgPrice = revenue / sales;
968            const webPriceWidget = document.querySelector('[data-widget="webPrice"]');
969            if (webPriceWidget) {
970                const priceSpans = webPriceWidget.querySelectorAll('span');
971                const prices = [];
972                priceSpans.forEach(span => {
973                    const text = span.textContent.trim();
974                    const match = text.match(/^(\d[\d\s]*)\s*₽$/);
975                    if (match) {
976                        const priceText = match[1].replace(/\s/g, '');
977                        const parsedPrice = parseInt(priceText);
978                        if (!isNaN(parsedPrice) && parsedPrice > 100 && parsedPrice < 100000) {
979                            prices.push(parsedPrice);
980                        }
981                    }
982                });
983                if (prices.length > 0) {
984                    avgPrice = Math.min(...prices);
985                    console.log('Found prices in webPrice:', prices, 'Using minimum:', avgPrice);
986                }
987            }
988            
989            const currentStock = currentStockText ? parseInt(currentStockText[1].replace(/\s/g, '')) : 0;
990            
991            const dataPoints = await extractDailyDataFromChart(widget);
992            
993            if (!dataPoints || dataPoints.length === 0) {
994                console.error('Failed to extract chart data');
995                return null;
996            }
997
998            const stockPoints = await extractStockData(widget);
999            console.log('Stock points extracted:', stockPoints);
1000
1001            const totalSales = dataPoints.reduce((sum, d) => sum + d.sales, 0);
1002            const avgDailySales = totalSales / dataPoints.length;
1003            
1004            let matchedStockPoints = null;
1005            if (stockPoints && stockPoints.length > 0) {
1006                console.log('Matching stock data with sales data...');
1007                matchedStockPoints = dataPoints.map(salesDay => {
1008                    const stockDay = stockPoints.find(s => s.day === salesDay.day);
1009                    return {
1010                        day: salesDay.day,
1011                        sales: salesDay.sales,
1012                        price: salesDay.price,
1013                        stock: stockDay ? stockDay.stock : null
1014                    };
1015                });
1016                console.log('Matched stock data - First 5 days:', matchedStockPoints.slice(0, 5));
1017                console.log('Matched stock data - Last 5 days:', matchedStockPoints.slice(-5));
1018            } else {
1019                console.log('No stock data to match');
1020            }
1021            
1022            console.log('Extracted summary data:', { 
1023                revenue, 
1024                sales,
1025                avgPrice, 
1026                currentStock, 
1027                avgDailySales,
1028                daysOfData: dataPoints.length,
1029                stockDataPoints: stockPoints ? stockPoints.length : 0,
1030                matchedDataPoints: matchedStockPoints ? matchedStockPoints.length : 0
1031            });
1032            
1033            return {
1034                revenue,
1035                sales,
1036                avgPrice,
1037                currentStock,
1038                avgDailySales,
1039                dataPoints,
1040                stockPoints,
1041                matchedStockPoints
1042            };
1043        }
1044
1045        return null;
1046    }
1047
1048    // Calculate demand elasticity from historical data
1049    function calculateDemandElasticity(dataPoints, matchedStockPoints) {
1050        console.log('=== CALCULATING DEMAND ELASTICITY (Bayesian Log-Linear) ===');
1051        console.log('dataPoints:', dataPoints);
1052        console.log('matchedStockPoints:', matchedStockPoints);
1053        
1054        // Filter out days with zero stock and the day before zero stock
1055        let validPoints = dataPoints;
1056        if (matchedStockPoints && matchedStockPoints.length > 0) {
1057            const zeroStockDays = new Set();
1058            matchedStockPoints.forEach((d, index) => {
1059                if (d.stock === 0) {
1060                    zeroStockDays.add(d.day);
1061                    // Also exclude the day before zero stock
1062                    if (index > 0) {
1063                        zeroStockDays.add(matchedStockPoints[index - 1].day);
1064                    }
1065                }
1066            });
1067            validPoints = matchedStockPoints.filter(d => !zeroStockDays.has(d.day));
1068            console.log(`Excluded ${zeroStockDays.size} days (zero stock and day before)`);
1069        }
1070        
1071        console.log(`Using ${validPoints.length} days for elasticity calculation`);
1072        console.log('Valid points sample:', validPoints.slice(0, 5));
1073        
1074        if (validPoints.length < 5) {
1075            console.log('Not enough data points for elasticity calculation, using default -1.5');
1076            return { elasticity: -1.5, reliability: 'bad', r2: 0, uniquePrices: 0, daysUsed: validPoints.length };
1077        }
1078        
1079        // === LOG-LINEAR REGRESSION ===
1080        // Transform to log space: log(sales) = intercept + elasticity * log(price)
1081        const logPrices = validPoints.map(d => Math.log(d.price));
1082        const logSales = validPoints.map(d => Math.log(d.sales + 1)); // +1 for stability when sales = 0
1083        
1084        const n = validPoints.length;
1085        const sumX = logPrices.reduce((a, b) => a + b, 0);
1086        const sumY = logSales.reduce((a, b) => a + b, 0);
1087        const sumXY = logPrices.reduce((a, b, i) => a + b * logSales[i], 0);
1088        const sumX2 = logPrices.reduce((a, b) => a + b * b, 0);
1089        
1090        console.log(`Log-linear regression: n=${n}, sumX=${sumX.toFixed(2)}, sumY=${sumY.toFixed(2)}, sumXY=${sumXY.toFixed(2)}, sumX2=${sumX2.toFixed(2)}`);
1091        
1092        const denominator = n * sumX2 - sumX * sumX;
1093        if (denominator === 0) {
1094            console.log('⚠️ Denominator is zero, using default elasticity');
1095            return { elasticity: -1.5, reliability: 'bad', r2: 0, uniquePrices: 0, daysUsed: n };
1096        }
1097        
1098        const slope = (n * sumXY - sumX * sumY) / denominator; // This is the elasticity
1099        const intercept = (sumY - slope * sumX) / n;
1100        
1101        console.log(`OLS results: slope (elasticity) = ${slope.toFixed(4)}, intercept = ${intercept.toFixed(4)}`);
1102        
1103        // Calculate R² (coefficient of determination)
1104        const yMean = sumY / n;
1105        const ssTotal = logSales.reduce((s, y) => s + Math.pow(y - yMean, 2), 0);
1106        const predicted = logPrices.map(x => slope * x + intercept);
1107        const ssResidual = logSales.reduce((s, y, i) => s + Math.pow(y - predicted[i], 2), 0);
1108        const r2 = ssTotal > 0 ? 1 - (ssResidual / ssTotal) : 0;
1109        
1110        console.log(`R²: ssTotal=${ssTotal.toFixed(4)}, ssResidual=${ssResidual.toFixed(4)}, R²=${r2.toFixed(4)}`);
1111        
1112        // === BAYESIAN CORRECTION WITH INFORMATIVE PRIOR ===
1113        const priorElasticity = -1.5;        // Typical value for Ozon products
1114        const priorStrength = 10;            // "Equivalent to 10 days of observations"
1115        
1116        console.log(`Prior: elasticity=${priorElasticity}, strength=${priorStrength} days`);
1117        
1118        const dataStrength = n;              // Weight of actual data
1119        const posteriorElasticity = (slope * dataStrength + priorElasticity * priorStrength) / (dataStrength + priorStrength);
1120        
1121        console.log(`Posterior elasticity (simple Bayesian average): ${posteriorElasticity.toFixed(4)}`);
1122        
1123        // If we have a lot of data and high R² - trust the data more
1124        const weightData = Math.min(1, n / 20) * Math.sqrt(Math.max(0, r2));
1125        const finalElasticity = slope * weightData + posteriorElasticity * (1 - weightData);
1126        
1127        console.log(`Data weight: ${weightData.toFixed(4)} (based on n=${n} and R²=${r2.toFixed(4)})`);
1128        console.log(`Final elasticity (weighted): ${finalElasticity.toFixed(4)}`);
1129        
1130        // Clamp to reasonable range
1131        const clampedElasticity = Math.max(-3.0, Math.min(-0.3, finalElasticity));
1132        
1133        if (clampedElasticity !== finalElasticity) {
1134            console.log(`Elasticity ${finalElasticity.toFixed(4)} clamped to ${clampedElasticity.toFixed(4)}`);
1135        }
1136        
1137        // Determine reliability based on R², number of unique prices, and days
1138        const uniquePrices = [...new Set(validPoints.map(d => d.price))];
1139        
1140        let reliability = 'bad';
1141        if (r2 >= 0.7 && uniquePrices.length >= 8 && n >= 20) {
1142            reliability = 'good';
1143        } else if (r2 >= 0.4 && uniquePrices.length >= 4 && n >= 10) {
1144            reliability = 'satisfactory';
1145        }
1146        
1147        console.log(`=== FINAL ELASTICITY: ${clampedElasticity.toFixed(4)}, R²=${r2.toFixed(4)}, Reliability=${reliability} ===`);
1148        console.log(`Raw OLS elasticity: ${slope.toFixed(4)}, Posterior: ${posteriorElasticity.toFixed(4)}, Final: ${clampedElasticity.toFixed(4)}`);
1149        
1150        return { 
1151            elasticity: clampedElasticity, 
1152            reliability: reliability, 
1153            r2: r2, 
1154            uniquePrices: uniquePrices.length, 
1155            daysUsed: n,
1156            rawElasticity: slope,
1157            posteriorElasticity: posteriorElasticity
1158        };
1159    }
1160
1161    // AI-powered Bayesian price optimization
1162    async function bayesianPriceOptimizationWithAI(historicalData, productData, competitorData, coinvest, drr) {
1163        console.log('=== ENTERED bayesianPriceOptimizationWithAI (v2.0.1) ===');
1164        console.log('Historical data:', historicalData);
1165        console.log('Product data:', productData);
1166        console.log('Competitor data:', competitorData);
1167        console.log('Coinvest:', coinvest, '%, DRR:', drr, '%');
1168        
1169        try {
1170            console.log('>>> ABOUT TO CALL calculateDemandElasticity <<<');
1171            console.log('>>> dataPoints:', historicalData.dataPoints);
1172            console.log('>>> matchedStockPoints:', historicalData.matchedStockPoints);
1173            
1174            const elasticityResult = calculateDemandElasticity(historicalData.dataPoints, historicalData.matchedStockPoints);
1175            const realElasticity = elasticityResult.elasticity;
1176            
1177            console.log(`>>> AFTER calculateDemandElasticity, realElasticity = ${realElasticity} <<<`);
1178            console.log(`Real demand elasticity calculated: ${realElasticity.toFixed(4)}, R²=${elasticityResult.r2.toFixed(4)}, Reliability=${elasticityResult.reliability}`);
1179            
1180            // Prepare historical data summary
1181            const uniquePrices = [...new Set(historicalData.dataPoints.map(d => d.price))];
1182            
1183            console.log(`Historical data: ${historicalData.dataPoints.length} days, ${uniquePrices.length} unique prices:`, uniquePrices);
1184            
1185            // Prepare competitor analysis
1186            let competitorAnalysis = '';
1187            if (competitorData && competitorData.length > 0) {
1188                const prices = competitorData.map(c => c.price);
1189                const minCompPrice = Math.min(...prices);
1190                const maxCompPrice = Math.max(...prices);
1191                const avgCompPrice = Math.round(prices.reduce((a, b) => a + b, 0) / prices.length);
1192                
1193                const topCompetitors = competitorData.slice(0, 3).map(c => 
1194                    `${c.price}₽ (${c.sales30days ? (c.sales30days / 30).toFixed(1) + ' шт/день' : 'н/д'})`
1195                ).join(', ');
1196                
1197                competitorAnalysis = `\nКОНКУРЕНТЫ (${competitorData.length} шт): цены ${minCompPrice}-${maxCompPrice}₽, средняя ${avgCompPrice}₽. Топ-3 по выручке: ${topCompetitors}.`;
1198                
1199                console.log('>>> COMPETITOR PRICES BEING SENT TO AI <<<');
1200                console.log('Competitor count:', competitorData.length);
1201                console.log('Price range:', minCompPrice, '-', maxCompPrice, '₽');
1202                console.log('Average price:', avgCompPrice, '₽');
1203                console.log('Top 3 competitors:', topCompetitors);
1204                console.log('All competitor prices:', prices);
1205                console.log('Competitor analysis text for AI:', competitorAnalysis);
1206            } else {
1207                console.log('>>> NO COMPETITOR DATA - AI WILL NOT CONSIDER COMPETITORS <<<');
1208            }
1209
1210            const commissionPercent = Math.round(productData.commission * 100);
1211            
1212            // Calculate actual price from current display price using user's coinvest value
1213            const displayPriceMultiplier = (100 - coinvest) / 100;
1214            const actualPrice = historicalData.avgPrice / displayPriceMultiplier;
1215            const minBreakevenActualPrice = (productData.cost + productData.delivery) / (1 - productData.commission - drr / 100);
1216            const minBreakevenDisplayPrice = Math.ceil(minBreakevenActualPrice * displayPriceMultiplier);
1217            
1218            // === НОВЫЕ МЕТРИКИ ===
1219            
1220            // 1. Weighted average competitor price (взвешенная по продажам)
1221            let weightedAvgCompPrice = 0;
1222            let totalCompSales = 0;
1223            let minCompPrice = Infinity;
1224            let maxCompPrice = 0;
1225            if (competitorData && competitorData.length > 0) {
1226                competitorData.forEach(c => {
1227                    if (c.sales30days > 0) {
1228                        weightedAvgCompPrice += c.price * c.sales30days;
1229                        totalCompSales += c.sales30days;
1230                    }
1231                    minCompPrice = Math.min(minCompPrice, c.price);
1232                    maxCompPrice = Math.max(maxCompPrice, c.price);
1233                });
1234                weightedAvgCompPrice = totalCompSales > 0 ? weightedAvgCompPrice / totalCompSales : historicalData.avgPrice;
1235            } else {
1236                weightedAvgCompPrice = historicalData.avgPrice;
1237                minCompPrice = historicalData.avgPrice;
1238                maxCompPrice = historicalData.avgPrice;
1239            }
1240            
1241            // 2. RPI (Relative Price Index)
1242            const currentDisplayPrice = historicalData.avgPrice;
1243            const rpi = (currentDisplayPrice / weightedAvgCompPrice) * 100;
1244            
1245            // 3. Popularity Score (твои средние продажи vs средние конкурентов)
1246            let avgCompDailySales = 0;
1247            if (competitorData && competitorData.length > 0) {
1248                avgCompDailySales = competitorData.reduce((sum, c) => sum + (c.sales30days || 0) / 30, 0) / competitorData.length;
1249            }
1250            const popularityScore = avgCompDailySales > 0 ? historicalData.avgDailySales / avgCompDailySales : 1;
1251            
1252            // 4. PVBI (Price Value Benefit Index) — proxy ценности
1253            let maxCompValue = 0;
1254            if (competitorData && competitorData.length > 0) {
1255                competitorData.forEach(c => {
1256                    const value = c.sales30days > 0 ? (c.sales30days / 30) / c.price : 0;
1257                    maxCompValue = Math.max(maxCompValue, value);
1258                });
1259            }
1260            const yourValue = historicalData.avgDailySales / currentDisplayPrice;
1261            const pvbi = maxCompValue > 0 ? yourValue / maxCompValue : 1;
1262            
1263            // 5. Days of Supply
1264            const daysOfSupply = historicalData.avgDailySales > 0 ? historicalData.currentStock / historicalData.avgDailySales : 999;
1265            
1266            // 6. Топ-3 конкурентов для промпта
1267            const topCompetitors = competitorData && competitorData.length > 0 
1268                ? competitorData.slice(0, 3).map(c => `${c.brand}: ${c.price}₽ (${(c.sales30days / 30).toFixed(1)} шт/день)`).join(', ')
1269                : 'нет данных';
1270            
1271            console.log('=== НОВЫЕ МЕТРИКИ ===');
1272            console.log('Weighted Avg Comp Price:', weightedAvgCompPrice.toFixed(0), '₽');
1273            console.log('RPI:', rpi.toFixed(1), '%');
1274            console.log('Popularity Score:', popularityScore.toFixed(2));
1275            console.log('PVBI:', pvbi.toFixed(2));
1276            console.log('Days of Supply:', daysOfSupply.toFixed(1));
1277            
1278            const aiPrompt = `Ты — эксперт по динамическому ценообразованию на маркетплейсах (Ozon). Твоя задача — найти цену реализации, которая МАКСИМИЗИРУЕТ ДНЕВНУЮ ПРИБЫЛЬ с учётом всех рисков.
1279
1280КРИТИЧЕСКИ ВАЖНО:
1281• Цена реализации — это цена, которую видит покупатель (после соинвеста ${coinvest}% от Ozon).
1282• Фактическая цена = Цена реализации / ${displayPriceMultiplier.toFixed(2)}.
1283• Все расходы (комиссия, ДРР) считаются от фактической цены.
1284• Прибыль = (Факт. цена - Себестоимость - Комиссия - Доставка - Реклама) × Прогноз продаж.
1285
1286ТЕКУЩАЯ СИТУАЦИЯ:
1287• Текущая цена реализации: ${Math.round(historicalData.avgPrice)}1288• Фактическая цена: ${Math.round(actualPrice)}1289• Средние продажи: ${historicalData.avgDailySales.toFixed(1)} шт/день
1290• Остаток: ${historicalData.currentStock} шт (Days of Supply: ${daysOfSupply.toFixed(1)} дней)
1291• Popularity Score (относительно конкурентов): ${popularityScore.toFixed(2)} (выше 1 — популярнее рынка)
1292• RPI (Relative Price Index): ${rpi.toFixed(1)}% (100% — средняя цена конкурентов по выручке)
1293• PVBI (Price Value Benefit Index): ${pvbi.toFixed(2)} (выше 1 — выше воспринимаемая ценность)
1294
1295ЭЛАСТИЧНОСТЬ СПРОСА (лог-линейная модель, ${historicalData.dataPoints.length} дней, ${uniquePrices.length} уникальных цен):
1296• Коэффициент эластичности: ${realElasticity.toFixed(4)}
1297• Формула прогноза: Прогноз продаж = ${historicalData.avgDailySales.toFixed(1)} × (цена / ${Math.round(historicalData.avgPrice)}) ** ${realElasticity.toFixed(4)}
1298• Достоверность: R² = ${elasticityResult.r2.toFixed(4)}, ${elasticityResult.reliability}
1299
1300СТРУКТУРА РАСХОДОВ:
1301• Себестоимость: ${productData.cost}1302• Комиссия Ozon: ${commissionPercent}% от факт. цены
1303• Доставка: ${productData.delivery}1304• ДРР: ${drr}% от факт. цены
1305• Минимальная безубыточная цена реализации: ${minBreakevenDisplayPrice}1306
1307КОНКУРЕНТЫ (${competitorData ? competitorData.length : 0} шт):
1308• Взвешенная средняя цена: ${Math.round(weightedAvgCompPrice)}1309• Диапазон: ${minCompPrice === Infinity ? 'н/д' : minCompPrice + '–' + maxCompPrice + ' ₽'}
1310• Топ-3 по выручке: ${topCompetitors}
1311
1312ДОПОЛНИТЕЛЬНЫЕ КОРРЕКТИРОВКИ (обязательно применяй):
13131. RPI-корректировка: если RPI > 110 — уменьши прогноз продаж на (RPI-100)/50; если RPI < 90 — увеличь на (100-RPI)/50.
13142. Остатки: если Days of Supply < 10 — повысь цену (меньше чувствительность к скидкам); если > 60 — можно агрессивнее снижать.
13153. Popularity Score: если > 1.2 — можно устанавливать цену выше рынка без сильного падения продаж.
1316
1317ТВОЯ ЗАДАЧА:
13181. Рассчитай прибыль для цен реализации от ${minBreakevenDisplayPrice} ₽ до ${Math.round(historicalData.avgPrice * 1.6)} ₽ с шагом 10 ₽.
13192. Для каждой цены применяй ВСЕ корректировки выше (RPI, остатки, популярность).
13203. Используй лог-линейную формулу: Прогноз = ${historicalData.avgDailySales.toFixed(1)} × (цена / ${Math.round(historicalData.avgPrice)}) ** ${realElasticity.toFixed(4)}
13214. Выбери цену с МАКСИМАЛЬНОЙ дневной прибылью.
13225. Также предложи 3 альтернативные цены для исследования (explorationPrices) — чуть ниже/выше оптимума.
1323
1324ВАЖНО: Не бойся рекомендовать изменение цены! Если расчеты показывают, что другая цена даст больше прибыли - рекомендуй её!
1325
1326Верни JSON строго по схеме с оптимальной ценой РЕАЛИЗАЦИИ (той, что дает максимальную прибыль/день).`;
1327
1328            console.log('>>> CALLING RM.aiCall <<<');
1329            const aiResponse = await RM.aiCall(aiPrompt, {
1330                type: 'json_schema',
1331                json_schema: {
1332                    name: 'price_optimization',
1333                    schema: {
1334                        type: 'object',
1335                        properties: {
1336                            optimalPrice: { type: 'number' },
1337                            minPrice: { type: 'number' },
1338                            maxPrice: { type: 'number' },
1339                            confidence: { type: 'number' },
1340                            reasoning: { type: 'string' },
1341                            explorationPrices: {
1342                                type: 'array',
1343                                items: { type: 'number' },
1344                                minItems: 3,
1345                                maxItems: 3
1346                            }
1347                        },
1348                        required: ['optimalPrice', 'minPrice', 'maxPrice', 'confidence', 'reasoning', 'explorationPrices']
1349                    }
1350                }
1351            });
1352
1353            console.log('>>> AI RESPONSE RECEIVED <<<');
1354            console.log('AI response:', aiResponse);
1355            console.log('AI optimalPrice:', aiResponse.optimalPrice);
1356            console.log('AI reasoning:', aiResponse.reasoning);
1357            console.log('AI confidence:', aiResponse.confidence);
1358            console.log('AI explorationPrices:', aiResponse.explorationPrices);
1359
1360            // Calculate all possible prices and find the one with maximum profit
1361            const priceRange = [];
1362            const step = (aiResponse.maxPrice - aiResponse.minPrice) / 20;
1363            
1364            for (let price = aiResponse.minPrice; price <= aiResponse.maxPrice; price += step) {
1365                priceRange.push(Math.round(price));
1366            }
1367            
1368            aiResponse.explorationPrices.forEach(p => {
1369                if (!priceRange.includes(Math.round(p))) {
1370                    priceRange.push(Math.round(p));
1371                }
1372            });
1373            
1374            priceRange.sort((a, b) => a - b);
1375
1376            const results = priceRange.map(displayPrice => {
1377                let estimatedSales = historicalData.avgDailySales * Math.pow(displayPrice / historicalData.avgPrice, realElasticity);
1378                
1379                // Calculate actual price from display price using user's coinvest
1380                const actualPrice = displayPrice / displayPriceMultiplier;
1381                const commission = actualPrice * productData.commission;
1382                const advertisingCost = actualPrice * (drr / 100);
1383                const delivery = productData.delivery;
1384                const profitPerUnit = actualPrice - productData.cost - commission - delivery - advertisingCost;
1385                const profit = profitPerUnit * estimatedSales;
1386                const margin = (profitPerUnit / actualPrice) * 100;
1387                
1388                return {
1389                    price: Math.round(displayPrice * 10) / 10,
1390                    actualPrice: Math.round(actualPrice * 10) / 10,
1391                    estimatedDailySales: Math.round(estimatedSales * 10) / 10,
1392                    estimatedDailyProfit: Math.round(profit * 10) / 10,
1393                    profitMargin: Math.round(margin * 10) / 10,
1394                    confidence: aiResponse.confidence,
1395                    commission: Math.round(commission * 10) / 10,
1396                    advertisingCost: Math.round(advertisingCost * 10) / 10,
1397                    delivery: delivery
1398                };
1399            });
1400
1401            // Find the price with maximum profit from our calculations
1402            const maxProfitResult = results.reduce((max, current) => 
1403                current.estimatedDailyProfit > max.estimatedDailyProfit ? current : max
1404            );
1405            
1406            console.log('>>> CALCULATED OPTIMAL PRICE <<<');
1407            console.log('Current price:', historicalData.avgPrice, '₽');
1408            console.log('AI suggested:', aiResponse.optimalPrice, '₽');
1409            console.log('Math optimal:', maxProfitResult.price, '₽ with profit:', maxProfitResult.estimatedDailyProfit, '₽/day');
1410            
1411            // Log all results sorted by profit
1412            const sortedByProfit = [...results].sort((a, b) => b.estimatedDailyProfit - a.estimatedDailyProfit);
1413            console.log('>>> TOP 10 PRICES BY PROFIT <<<');
1414            sortedByProfit.slice(0, 10).forEach((r, i) => {
1415                console.log(`${i + 1}. Price: ${r.price}₽, Profit: ${r.estimatedDailyProfit}₽/day, Sales: ${r.estimatedDailySales} шт/day, Margin: ${r.profitMargin}%`);
1416            });
1417            
1418            console.log('>>> BOTTOM 5 PRICES BY PROFIT <<<');
1419            sortedByProfit.slice(-5).forEach((r, i) => {
1420                console.log(`${sortedByProfit.length - 4 + i}. Price: ${r.price}₽, Profit: ${r.estimatedDailyProfit}₽/day, Sales: ${r.estimatedDailySales} шт/day`);
1421            });
1422            
1423            // Use the mathematically optimal price instead of AI suggestion
1424            let optimalResult = maxProfitResult;
1425            
1426            // Update AI reasoning to reflect the correction - FIX: use currentDailyProfit instead of 0
1427            if (Math.abs(maxProfitResult.price - aiResponse.optimalPrice) > 5) {
1428                const aiSuggestedResult = results.find(r => Math.abs(r.price - aiResponse.optimalPrice) < 1);
1429                const aiSuggestedProfit = aiSuggestedResult ? aiSuggestedResult.estimatedDailyProfit : 0;
1430                
1431                // Calculate current profit correctly
1432                const displayPriceMultiplier = (100 - coinvest) / 100;
1433                const currentActualPrice = historicalData.avgPrice / displayPriceMultiplier;
1434                const currentCommission = currentActualPrice * productData.commission;
1435                const currentAdvertisingCost = currentActualPrice * (drr / 100);
1436                const currentDelivery = productData.delivery;
1437                const currentProfitPerUnit = currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost;
1438                const currentDailyProfit = Math.round(currentProfitPerUnit * historicalData.avgDailySales * 10) / 10;
1439                
1440                aiResponse.reasoning = `Математический расчет показал, что оптимальная цена ${maxProfitResult.price}₽ дает прибыль ${maxProfitResult.estimatedDailyProfit}₽/день, что лучше первоначально предложенной ${aiResponse.optimalPrice}₽ (прибыль ${aiSuggestedProfit}₽/день) и текущей ${Math.round(historicalData.avgPrice)}₽ (прибыль ${currentDailyProfit}₽/день). При цене ${maxProfitResult.price}₽: продажи ${maxProfitResult.estimatedDailySales} шт/день, маржа ${maxProfitResult.profitMargin}%, прибыль/шт ${Math.round(maxProfitResult.actualPrice - productData.cost - maxProfitResult.commission - maxProfitResult.delivery - maxProfitResult.advertisingCost)}₽. Эта цена максимизирует дневную прибыль с учетом эластичности спроса и конкурентной среды.`;
1441                console.log('>>> CORRECTED AI SUGGESTION <<<');
1442                console.log('New reasoning:', aiResponse.reasoning);
1443            }
1444
1445            const alternatives = [];
1446            aiResponse.explorationPrices.forEach(explorePrice => {
1447                if (explorePrice !== aiResponse.optimalPrice) {
1448                    let altResult = results.find(r => r.price === explorePrice);
1449                    
1450                    if (!altResult) {
1451                        const estimatedSales = historicalData.avgDailySales * Math.pow(explorePrice / historicalData.avgPrice, realElasticity);
1452                        
1453                        const actualPrice = explorePrice / displayPriceMultiplier;
1454                        const commission = actualPrice * productData.commission;
1455                        const advertisingCost = actualPrice * (drr / 100);
1456                        const delivery = productData.delivery;
1457                        const profit = (actualPrice - productData.cost - commission - delivery - advertisingCost) * estimatedSales;
1458                        const margin = ((actualPrice - productData.cost - commission - delivery - advertisingCost) / actualPrice) * 100;
1459                        
1460                        altResult = {
1461                            price: Math.round(explorePrice * 10) / 10,
1462                            actualPrice: Math.round(actualPrice * 10) / 10,
1463                            estimatedDailySales: Math.round(estimatedSales * 10) / 10,
1464                            estimatedDailyProfit: Math.round(profit * 10) / 10,
1465                            profitMargin: Math.round(margin * 10) / 10,
1466                            confidence: aiResponse.confidence,
1467                            commission: Math.round(commission * 10) / 10,
1468                            advertisingCost: Math.round(advertisingCost * 10) / 10,
1469                            delivery: delivery
1470                        };
1471                    }
1472                    
1473                    alternatives.push(altResult);
1474                }
1475            });
1476
1477            console.log('>>> RETURNING OPTIMIZATION RESULTS <<<');
1478            return {
1479                optimal: optimalResult,
1480                alternatives: alternatives,
1481                currentPrice: Math.round(historicalData.avgPrice),
1482                productData: productData,
1483                allResults: results,
1484                aiReasoning: aiResponse.reasoning,
1485                aiConfidence: aiResponse.confidence,
1486                aiDemandElasticity: realElasticity,
1487                elasticityReliability: elasticityResult.reliability,
1488                elasticityR2: elasticityResult.r2,
1489                elasticityUniquePrices: elasticityResult.uniquePrices,
1490                elasticityDaysUsed: elasticityResult.daysUsed,
1491                explorationPrices: aiResponse.explorationPrices,
1492                competitorData: competitorData,
1493                historicalData: historicalData,
1494                coinvest: coinvest,
1495                drr: drr
1496            };
1497
1498        } catch (error) {
1499            console.error('AI analysis failed:', error);
1500            throw error;
1501        }
1502    }
1503
1504    // Create and inject the analysis widget
1505    function createAnalysisWidget() {
1506        console.log('Creating analysis widget (v2.0.1)...');
1507        
1508        if (document.getElementById('bayesian-price-optimizer')) {
1509            console.log('Widget already exists');
1510            return;
1511        }
1512
1513        const widget = document.createElement('div');
1514        widget.id = 'bayesian-price-optimizer';
1515        widget.innerHTML = `
1516            <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 
1517                        color: white; 
1518                        padding: 15px; 
1519                        border-radius: 12px; 
1520                        margin: 15px 0; 
1521                        box-shadow: 0 4px 15px rgba(0,0,0,0.2);
1522                        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1523                        width: 100%;
1524                        box-sizing: border-box;">
1525                <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px;">
1526                    <h3 style="margin: 0; font-size: 16px; font-weight: 600;">
1527                        🎯 Оптимизация цены (AI + Bayesian) v2.0.1
1528                    </h3>
1529                </div>
1530                
1531                <div style="margin-bottom: 12px;">
1532                    <label style="display: block; font-size: 12px; margin-bottom: 4px; opacity: 0.9;">
1533                        Ключевой запрос для поиска конкурентов
1534                    </label>
1535                    <input type="text" id="key-query-input" placeholder="Например: крем для лица увлажняющий"
1536                           style="width: 100%; padding: 8px; border: none; border-radius: 6px; 
1537                                  font-size: 14px; box-sizing: border-box;">
1538                </div>
1539                
1540                <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px;">
1541                    <div>
1542                        <label style="display: block; font-size: 12px; margin-bottom: 4px; opacity: 0.9;">
1543                            Соинвест (скидка OZON), %
1544                        </label>
1545                        <input type="number" id="coinvest-input" value="45" min="0" max="100" step="1"
1546                               style="width: 100%; padding: 8px; border: none; border-radius: 6px; 
1547                                      font-size: 14px; box-sizing: border-box; font-weight: 600;">
1548                    </div>
1549                    <div>
1550                        <label style="display: block; font-size: 12px; margin-bottom: 4px; opacity: 0.9;">
1551                            ДРР (расходы на рекламу), %
1552                        </label>
1553                        <input type="number" id="drr-input" value="0" min="0" max="100" step="0.1"
1554                               style="width: 100%; padding: 8px; border: none; border-radius: 6px; 
1555                                      font-size: 14px; box-sizing: border-box; font-weight: 600;">
1556                    </div>
1557                </div>
1558                
1559                <button id="analyze-price-btn" style="background: white; 
1560                                                       color: #667eea; 
1561                                                       border: none; 
1562                                                       padding: 10px 20px; 
1563                                                       border-radius: 8px; 
1564                                                       cursor: pointer; 
1565                                                       font-weight: 600;
1566                                                       font-size: 14px;
1567                                                       transition: all 0.3s;
1568                                                       width: 100%;">
1569                    Анализировать
1570                </button>
1571                
1572                <div id="analysis-results" style="display: none; margin-top: 15px;">
1573                    <div style="background: rgba(255,255,255,0.15); 
1574                                padding: 12px; 
1575                                border-radius: 8px; 
1576                                backdrop-filter: blur(10px);
1577                                max-width: 600px; box-sizing: border-box;">
1578                        <div id="results-content" style="overflow-wrap: break-word; word-wrap: break-word;"></div>
1579                    </div>
1580                </div>
1581                <div id="loading-indicator" style="display: none; text-align: center; padding: 20px;">
1582                    <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>
1583                    <p style="margin-top: 10px; font-size: 13px;">Анализируем данные с помощью AI...</p>
1584                </div>
1585            </div>
1586        `;
1587
1588        const style = document.createElement('style');
1589        style.textContent = `
1590            @keyframes spin {
1591                to { transform: rotate(360deg); }
1592            }
1593            #analyze-price-btn:hover {
1594                transform: translateY(-2px);
1595                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
1596            }
1597            #bayesian-price-optimizer * {
1598                box-sizing: border-box;
1599            }
1600        `;
1601        document.head.appendChild(style);
1602
1603        const mpsWidget = document.querySelector('.mps-sidebar');
1604        if (mpsWidget) {
1605            mpsWidget.parentElement.insertBefore(widget, mpsWidget.nextSibling);
1606            console.log('Widget inserted after MP Stats');
1607        } else {
1608            document.body.appendChild(widget);
1609            console.log('Widget inserted at body end');
1610        }
1611
1612        const analyzeBtn = document.getElementById('analyze-price-btn');
1613        analyzeBtn.addEventListener('click', performAnalysis);
1614    }
1615
1616    // Perform the price analysis
1617    async function performAnalysis() {
1618        console.log('>>> performAnalysis CALLED (v2.0.1) <<<');
1619        
1620        const loadingIndicator = document.getElementById('loading-indicator');
1621        const resultsDiv = document.getElementById('analysis-results');
1622        
1623        loadingIndicator.style.display = 'block';
1624        resultsDiv.style.display = 'none';
1625
1626        try {
1627            // Get user input values
1628            const coinvestInput = document.getElementById('coinvest-input');
1629            const drrInput = document.getElementById('drr-input');
1630            const keyQueryInput = document.getElementById('key-query-input');
1631            
1632            const coinvest = parseFloat(coinvestInput.value) || 45;
1633            const drr = parseFloat(drrInput.value) || 0;
1634            const keyQuery = keyQueryInput.value.trim();
1635            
1636            console.log('User inputs - Coinvest:', coinvest, '%, DRR:', drr, '%, Key Query:', keyQuery);
1637            
1638            // Validate inputs
1639            if (coinvest < 0 || coinvest > 100) {
1640                throw new Error('Соинвест должен быть от 0 до 100%');
1641            }
1642            if (drr < 0 || drr > 100) {
1643                throw new Error('ДРР должен быть от 0 до 100%');
1644            }
1645            if (!keyQuery) {
1646                throw new Error('Пожалуйста, введите ключевой запрос для поиска конкурентов');
1647            }
1648            
1649            const productId = getProductId();
1650            console.log('Product ID:', productId);
1651            
1652            if (!productId) {
1653                throw new Error('Не удалось определить ID товара');
1654            }
1655
1656            const shortSku = getShortSku(productId);
1657            console.log('Short SKU:', shortSku);
1658            
1659            if (!shortSku) {
1660                throw new Error('Данные для этого товара не найдены');
1661            }
1662            
1663            const productData = PRODUCT_DATA[shortSku];
1664            console.log('Product data:', productData);
1665            
1666            if (!productData) {
1667                throw new Error('Данные для этого товара не найдены');
1668            }
1669
1670            console.log('>>> CALLING extractMPStatsData <<<');
1671            const mpStatsData = await extractMPStatsData();
1672            console.log('>>> extractMPStatsData FINISHED <<<');
1673            
1674            if (!mpStatsData) {
1675                throw new Error('Не удалось извлечь данные из MP Stats');
1676            }
1677
1678            // Save analysis state before opening search tab
1679            await GM.setValue('analysis_state', JSON.stringify({
1680                coinvest,
1681                drr,
1682                keyQuery,
1683                productId,
1684                shortSku,
1685                mpStatsData,
1686                productData,
1687                timestamp: Date.now()
1688            }));
1689            console.log('Analysis state saved, opening search tab...');
1690
1691            // Clear previous competitor data
1692            await GM.deleteValue('temp_competitors');
1693            await GM.deleteValue('competitors_extracted');
1694
1695            console.log('>>> CALLING extractCompetitorsFromSearch <<<');
1696            await extractCompetitorsFromSearch(keyQuery);
1697            
1698            // Wait for competitors to be extracted (poll for data)
1699            console.log('Waiting for competitor data...');
1700            let attempts = 0;
1701            const maxAttempts = 90; // 90 seconds max (increased from 60)
1702            
1703            while (attempts < maxAttempts) {
1704                await new Promise(resolve => setTimeout(resolve, 1000));
1705                
1706                const extracted = await GM.getValue('competitors_extracted', null);
1707                if (extracted === 'true') {
1708                    console.log('Competitors extracted successfully, continuing analysis...');
1709                    break;
1710                }
1711                
1712                if (extracted === 'failed') {
1713                    throw new Error('Не удалось извлечь данные о конкурентах из MPStats');
1714                }
1715                
1716                attempts++;
1717                if (attempts % 10 === 0) {
1718                    console.log(`Waiting for competitors... ${attempts}/${maxAttempts} seconds`);
1719                }
1720            }
1721            
1722            if (attempts >= maxAttempts) {
1723                throw new Error('Timeout: не удалось получить данные о конкурентах за 90 секунд');
1724            }
1725            
1726            // Get competitors from storage
1727            const competitorsJson = await GM.getValue('temp_competitors', null);
1728            if (!competitorsJson) {
1729                throw new Error('Не удалось получить данные о конкурентах');
1730            }
1731
1732            const competitorData = JSON.parse(competitorsJson);
1733            console.log('Competitors loaded:', competitorData);
1734
1735            // Clear state
1736            await GM.deleteValue('analysis_state');
1737            await GM.deleteValue('temp_competitors');
1738            await GM.deleteValue('competitors_extracted');
1739
1740            console.log('>>> CALLING bayesianPriceOptimizationWithAI <<<');
1741            const optimization = await bayesianPriceOptimizationWithAI(
1742                mpStatsData, 
1743                productData, 
1744                competitorData, 
1745                coinvest, 
1746                drr
1747            );
1748            console.log('>>> bayesianPriceOptimizationWithAI FINISHED <<<');
1749            
1750            if (!optimization) {
1751                throw new Error('Ошибка при оптимизации цены');
1752            }
1753
1754            displayResults(optimization, coinvest, drr);
1755            
1756        } catch (error) {
1757            console.error('Analysis error:', error);
1758            console.error('Error message:', error.message);
1759            console.error('Error stack:', error.stack);
1760            const resultsContent = document.getElementById('results-content');
1761            resultsContent.innerHTML = `
1762                <div style="color: #fee; padding: 10px; text-align: center;">
1763                    <strong>⚠️ Ошибка:</strong><br>
1764                    ${error.message || 'Неизвестная ошибка'}
1765                </div>
1766            `;
1767            resultsDiv.style.display = 'block';
1768        } finally {
1769            loadingIndicator.style.display = 'none';
1770        }
1771    }
1772
1773    // Display optimization results
1774    function displayResults(optimization, coinvest, drr) {
1775        const resultsDiv = document.getElementById('analysis-results');
1776        const resultsContent = document.getElementById('results-content');
1777        
1778        const { optimal, alternatives, currentPrice, productData, allResults, aiReasoning, competitorData, historicalData } = optimization;
1779        
1780        const currentDailySales = historicalData.avgDailySales;
1781        
1782        // Calculate actual price from display price using user's coinvest value
1783        const displayPriceMultiplier = (100 - coinvest) / 100;
1784        const currentActualPrice = currentPrice / displayPriceMultiplier;
1785        const currentCommission = currentActualPrice * productData.commission;
1786        const currentAdvertisingCost = currentActualPrice * (drr / 100);
1787        const currentDelivery = productData.delivery;
1788        const currentDailyProfit = Math.round((currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost) * currentDailySales * 10) / 10;
1789        const currentDailyRevenue = Math.round(currentPrice * currentDailySales * 10) / 10;
1790        const currentMargin = Math.round(((currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost) / currentActualPrice) * 100 * 10) / 10;
1791        const currentProfitPerUnit = Math.round(currentActualPrice - productData.cost - currentCommission - currentDelivery - currentAdvertisingCost);
1792        
1793        // Calculate percentages for current price
1794        const currentCommissionPercent = Math.round((currentCommission / currentActualPrice) * 100 * 10) / 10;
1795        const currentDeliveryPercent = Math.round((currentDelivery / currentActualPrice) * 100 * 10) / 10;
1796        const currentCostPercent = Math.round((productData.cost / currentActualPrice) * 100 * 10) / 10;
1797        const currentDrrPercent = Math.round((currentAdvertisingCost / currentActualPrice) * 100 * 10) / 10;
1798        
1799        const optimalDailyRevenue = Math.round(optimal.price * optimal.estimatedDailySales * 10) / 10;
1800        const optimalProfitPerUnit = Math.round(optimal.actualPrice - productData.cost - optimal.commission - optimal.delivery - optimal.advertisingCost);
1801        
1802        // Calculate percentages for optimal price
1803        const optimalCommissionPercent = Math.round((optimal.commission / optimal.actualPrice) * 100 * 10) / 10;
1804        const optimalDeliveryPercent = Math.round((optimal.delivery / optimal.actualPrice) * 100 * 10) / 10;
1805        const optimalCostPercent = Math.round((productData.cost / optimal.actualPrice) * 100 * 10) / 10;
1806        const optimalDrrPercent = Math.round((optimal.advertisingCost / optimal.actualPrice) * 100 * 10) / 10;
1807        
1808        const priceChange = Math.round(((optimal.price - currentPrice) / currentPrice) * 100);
1809        const priceDiff = optimal.price - currentPrice;
1810        const actualPriceChange = Math.round(((optimal.actualPrice - currentActualPrice) / currentActualPrice) * 100);
1811        const actualPriceDiff = Math.round(optimal.actualPrice - currentActualPrice);
1812        const profitChange = Math.round(((optimal.estimatedDailyProfit - currentDailyProfit) / Math.abs(currentDailyProfit)) * 100);
1813        const profitDiff = Math.round(optimal.estimatedDailyProfit - currentDailyProfit);
1814        const revenueChange = Math.round(((optimalDailyRevenue - currentDailyRevenue) / currentDailyRevenue) * 100);
1815        const revenueDiff = Math.round(optimalDailyRevenue - currentDailyRevenue);
1816        const salesChange = Math.round(((optimal.estimatedDailySales - currentDailySales) / currentDailySales) * 100);
1817        const salesDiff = Math.round((optimal.estimatedDailySales - currentDailySales) * 10) / 10;
1818        const marginChange = Math.round((optimal.profitMargin - currentMargin) * 10) / 10;
1819        const profitPerUnitChange = currentProfitPerUnit > 0 ? Math.round(((optimalProfitPerUnit - currentProfitPerUnit) / currentProfitPerUnit) * 100) : 0;
1820        const profitPerUnitDiff = optimalProfitPerUnit - currentProfitPerUnit;
1821        
1822        // Calculate percentage changes for costs
1823        const commissionPercentChange = Math.round((optimalCommissionPercent - currentCommissionPercent) * 10) / 10;
1824        const deliveryPercentChange = Math.round((optimalDeliveryPercent - currentDeliveryPercent) * 10) / 10;
1825        const costPercentChange = Math.round((optimalCostPercent - currentCostPercent) * 10) / 10;
1826        const drrPercentChange = Math.round((optimalDrrPercent - currentDrrPercent) * 10) / 10;
1827        
1828        // Format AI reasoning with line breaks
1829        const formattedReasoning = aiReasoning
1830            .replace(/\. /g, '.<br>• ')
1831            .replace(/^/, '• ');
1832        
1833        // Determine elasticity reliability color and text
1834        let reliabilityColor = '#ef4444'; // red for bad
1835        let reliabilityText = 'Плохо';
1836        let reliabilityIcon = '⚠️';
1837        
1838        if (optimization.elasticityReliability === 'good') {
1839            reliabilityColor = '#10b981'; // green
1840            reliabilityText = 'Хорошо';
1841            reliabilityIcon = '✅';
1842        } else if (optimization.elasticityReliability === 'satisfactory') {
1843            reliabilityColor = '#f59e0b'; // orange
1844            reliabilityText = 'Удовлетворительно';
1845            reliabilityIcon = '⚡';
1846        }
1847        
1848        let html = `
1849            <div style="background: rgba(59, 130, 246, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #3b82f6;">
1850                <div style="font-size: 13px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">📊 Эластичность спроса:</div>
1851                <div style="font-size: 14px; line-height: 1.6; opacity: 0.95;">
1852                    <div style="margin-bottom: 4px;">
1853                        <strong>Коэффициент:</strong> ${optimization.aiDemandElasticity.toFixed(4)} 
1854                        <span style="font-size: 13px; opacity: 0.8;">(при изменении цены на 1%, продажи изменятся на ${(optimization.aiDemandElasticity * 100).toFixed(1)}%)</span>
1855                    </div>
1856                    <div style="margin-bottom: 4px;">
1857                        <strong>Достоверность:</strong> 
1858                        <span style="color: ${reliabilityColor}; font-weight: 600;">${reliabilityIcon} ${reliabilityText}</span>
1859                    </div>
1860                    <div style="font-size: 12px; opacity: 0.8;">
1861                        R² = ${optimization.elasticityR2.toFixed(4)}${optimization.elasticityUniquePrices} уникальных цен • ${optimization.elasticityDaysUsed} дней данных
1862                    </div>
1863                </div>
1864            </div>
1865            
1866            <div style="background: rgba(16, 185, 129, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #10b981;">
1867                <div style="font-size: 13px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">🤖 Рекомендация AI:</div>
1868                <div style="font-size: 14px; line-height: 1.6; opacity: 0.95;">${formattedReasoning}</div>
1869            </div>
1870        `;
1871        
1872        if (competitorData && competitorData.length > 0) {
1873            // Calculate total revenue for percentage
1874            const totalRevenue = competitorData.reduce((sum, c) => sum + c.revenue30days, 0);
1875            
1876            html += `
1877            <div style="background: rgba(139, 92, 246, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #8b5cf6;">
1878                <div style="font-size: 13px; font-weight: 600; margin-bottom: 8px; opacity: 0.9;">
1879                    🏪 Конкуренты (${competitorData.length} шт):
1880                </div>
1881                <div style="overflow-x: auto;">
1882                    <table style="width: 100%; border-collapse: collapse; font-size: 12px;">
1883                        <thead>
1884                            <tr style="border-bottom: 1px solid rgba(255,255,255,0.3);">
1885                                <th style="text-align: left; padding: 6px; opacity: 0.9;">#</th>
1886                                <th style="text-align: left; padding: 6px; opacity: 0.9;">Бренд</th>
1887                                <th style="text-align: right; padding: 6px; opacity: 0.9;">Цена</th>
1888                                <th style="text-align: right; padding: 6px; opacity: 0.9;">Продажи</th>
1889                                <th style="text-align: right; padding: 6px; opacity: 0.9;">Выручка</th>
1890                                <th style="text-align: right; padding: 6px; opacity: 0.9;">% выручки</th>
1891                            </tr>
1892                        </thead>
1893                        <tbody>
1894            `;
1895            
1896            competitorData.slice(0, 10).forEach((comp, index) => {
1897                const competitorUrl = comp.sku ? `https://www.ozon.ru/product/${comp.sku}/` : '#';
1898                const salesInfo = comp.sales30days ? `${comp.sales30days} шт` : 'н/д';
1899                const revenueInfo = comp.revenue30days ? `${comp.revenue30days.toLocaleString()}` : 'н/д';
1900                const revenuePercent = totalRevenue > 0 ? ((comp.revenue30days / totalRevenue) * 100).toFixed(1) : '0.0';
1901                
1902                html += `
1903                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
1904                        <td style="padding: 6px; opacity: 0.8;">${index + 1}</td>
1905                        <td style="padding: 6px;">
1906                            <a href="${competitorUrl}" target="_blank" style="color: white; text-decoration: none; opacity: 0.9;">
1907                                ${comp.brand || 'N/A'}
1908                            </a>
1909                        </td>
1910                        <td style="padding: 6px; text-align: right; font-weight: 600;">${comp.price.toLocaleString()} ₽</td>
1911                        <td style="padding: 6px; text-align: right;">${salesInfo}</td>
1912                        <td style="padding: 6px; text-align: right; font-weight: 600;">${revenueInfo}</td>
1913                        <td style="padding: 6px; text-align: right; opacity: 0.9;">${revenuePercent}%</td>
1914                    </tr>
1915                `;
1916            });
1917            
1918            html += `
1919                        </tbody>
1920                    </table>
1921                </div>
1922            </div>
1923            `;
1924            
1925            // === NEW: Calculate recommended prices based on competitors ===
1926            
1927            // ШАГ 1: Средневзвешенная цена (вес 40%)
1928            let weightedSum = 0;
1929            let totalWeight = 0;
1930            competitorData.forEach((comp, index) => {
1931                const position = index + 1;
1932                const weight = position <= 5 ? comp.revenue30days * 2 : comp.revenue30days;
1933                weightedSum += comp.price * weight;
1934                totalWeight += weight;
1935            });
1936            const weightedAvgPrice = totalWeight > 0 ? Math.round(weightedSum / totalWeight) : 0;
1937            
1938            // ШАГ 2: Цена с лучшей конверсией (вес 30%)
1939            const competitorsWithConversion = competitorData.map(comp => ({
1940                ...comp,
1941                conversion: comp.sales30days > 0 ? comp.sales30days / comp.price : 0
1942            }));
1943            competitorsWithConversion.sort((a, b) => b.conversion - a.conversion);
1944            const top3Conversion = competitorsWithConversion.slice(0, 3);
1945            const bestConversionPrice = top3Conversion.length > 0 
1946                ? Math.round(top3Conversion.reduce((sum, c) => sum + c.price, 0) / top3Conversion.length)
1947                : 0;
1948            
1949            // ШАГ 3: Медианная цена топ-10 (вес 30%)
1950            const top10Prices = competitorData.slice(0, 10).map(c => c.price).sort((a, b) => a - b);
1951            let medianPrice = 0;
1952            if (top10Prices.length > 0) {
1953                const mid = Math.floor(top10Prices.length / 2);
1954                medianPrice = top10Prices.length % 2 === 0 
1955                    ? Math.round((top10Prices[mid - 1] + top10Prices[mid]) / 2)
1956                    : top10Prices[mid];
1957            }
1958            
1959            // ШАГ 3.5: Эластичность запроса (на основе данных конкурентов)
1960            let queryElasticity = -1.5; // default
1961            let queryElasticityR2 = 0;
1962            
1963            if (competitorData.length >= 5) {
1964                console.log('=== CALCULATING QUERY ELASTICITY (Cross-Sectional) ===');
1965                console.log('Using competitor data:', competitorData.map(c => `${c.brand}: ${c.price}₽, ${c.sales30days} шт/30д`));
1966                
1967                // Используем лог-линейную регрессию для конкурентов
1968                const logPrices = competitorData.map(c => Math.log(c.price));
1969                const logSales = competitorData.map(c => Math.log(c.sales30days + 1));
1970                
1971                console.log('Log prices:', logPrices.map(p => p.toFixed(4)));
1972                console.log('Log sales:', logSales.map(s => s.toFixed(4)));
1973                
1974                const n = competitorData.length;
1975                const sumX = logPrices.reduce((a, b) => a + b, 0);
1976                const sumY = logSales.reduce((a, b) => a + b, 0);
1977                const sumXY = logPrices.reduce((a, b, i) => a + b * logSales[i], 0);
1978                const sumX2 = logPrices.reduce((a, b) => a + b * b, 0);
1979                
1980                console.log(`Query elasticity regression: n=${n}, sumX=${sumX.toFixed(2)}, sumY=${sumY.toFixed(2)}, sumXY=${sumXY.toFixed(2)}, sumX2=${sumX2.toFixed(2)}`);
1981                
1982                const denominator = n * sumX2 - sumX * sumX;
1983                console.log('Denominator:', denominator.toFixed(4));
1984                
1985                if (denominator !== 0) {
1986                    const slope = (n * sumXY - sumX * sumY) / denominator;
1987                    const intercept = (sumY - slope * sumX) / n;
1988                    
1989                    console.log(`Query OLS results: slope (elasticity) = ${slope.toFixed(4)}, intercept = ${intercept.toFixed(4)}`);
1990                    
1991                    // Calculate R²
1992                    const yMean = sumY / n;
1993                    const ssTotal = logSales.reduce((s, y) => s + Math.pow(y - yMean, 2), 0);
1994                    const predicted = logPrices.map(x => slope * x + intercept);
1995                    const ssResidual = logSales.reduce((s, y, i) => s + Math.pow(y - predicted[i], 2), 0);
1996                    const r2 = ssTotal > 0 ? 1 - (ssResidual / ssTotal) : 0;
1997                    
1998                    console.log(`Query R²: ssTotal=${ssTotal.toFixed(4)}, ssResidual=${ssResidual.toFixed(4)}, R²=${r2.toFixed(4)}`);
1999                    
2000                    // Clamp to reasonable range
2001                    queryElasticity = Math.max(-3.0, Math.min(-0.3, slope));
2002                    queryElasticityR2 = r2;
2003                    
2004                    console.log('Query elasticity calculated:', queryElasticity.toFixed(4), 'R²:', r2.toFixed(4));
2005                    console.log('⚠️ NOTE: Cross-sectional elasticity may differ from time-series elasticity due to brand effects, quality differences, and search position');
2006                } else {
2007                    console.log('⚠️ Query elasticity: denominator is zero, using default -1.5');
2008                }
2009            }
2010            
2011            // ШАГ 4: Базовая оптимальная цена
2012            const baseOptimalPrice = Math.round(
2013                weightedAvgPrice * 0.4 + 
2014                bestConversionPrice * 0.3 + 
2015                medianPrice * 0.3
2016            );
2017            
2018            // ШАГ 6: Три стратегии
2019            const marketCapturePrice = Math.round(baseOptimalPrice * 0.85);
2020            const optimalStrategyPrice = baseOptimalPrice;
2021            const premiumPrice = Math.round(baseOptimalPrice * 1.15);
2022            
2023            html += `
2024            <div style="background: rgba(236, 72, 153, 0.2); padding: 10px; border-radius: 8px; margin-bottom: 12px; border-left: 4px solid #ec4899;">
2025                <div style="font-size: 13px; font-weight: 600; margin-bottom: 8px; opacity: 0.9;">
2026                    💰 Рекомендованные цены для запроса
2027                </div>
2028                
2029                <div style="margin-bottom: 10px; padding: 8px; background: rgba(255,255,255,0.1); border-radius: 6px;">
2030                    <div style="font-size: 12px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">📈 Базовые метрики:</div>
2031                    <div style="font-size: 13px; line-height: 1.8;">
2032                        <div>• <strong>Средневзвешенная цена:</strong> ${weightedAvgPrice} ₽ <span style="opacity: 0.7;">(вес 40%)</span></div>
2033                        <div>• <strong>Цена с лучшей конверсией:</strong> ${bestConversionPrice} ₽ <span style="opacity: 0.7;">(вес 30%)</span></div>
2034                        <div>• <strong>Медианная цена топ-10:</strong> ${medianPrice} ₽ <span style="opacity: 0.7;">(вес 30%)</span></div>
2035                        <div>• <strong>Эластичность запроса:</strong> ${queryElasticity.toFixed(4)} <span style="opacity: 0.7;">(R² = ${queryElasticityR2.toFixed(3)}, ${competitorData.length} конкурентов)</span></div>
2036                    </div>
2037                </div>
2038                
2039                <div style="font-size: 12px; font-weight: 600; margin-bottom: 6px; opacity: 0.9;">🎯 Стратегии ценообразования:</div>
2040                <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;">
2041                    <div style="background: rgba(239, 68, 68, 0.3); padding: 8px; border-radius: 6px; text-align: center;">
2042                        <div style="font-size: 11px; opacity: 0.8; margin-bottom: 4px;">🔥 Захват рынка</div>
2043                        <div style="font-size: 18px; font-weight: 700;">${marketCapturePrice} ₽</div>
2044                        <div style="font-size: 10px; opacity: 0.7; margin-top: 2px;">-15% от базовой</div>
2045                    </div>
2046                    <div style="background: rgba(16, 185, 129, 0.3); padding: 8px; border-radius: 6px; text-align: center;">
2047                        <div style="font-size: 11px; opacity: 0.8; margin-bottom: 4px;">⚖️ Оптимальная</div>
2048                        <div style="font-size: 18px; font-weight: 700;">${optimalStrategyPrice} ₽</div>
2049                        <div style="font-size: 10px; opacity: 0.7; margin-top: 2px;">базовая цена</div>
2050                    </div>
2051                    <div style="background: rgba(245, 158, 11, 0.3); padding: 8px; border-radius: 6px; text-align: center;">
2052                        <div style="font-size: 11px; opacity: 0.8; margin-bottom: 4px;">👑 Премиум</div>
2053                        <div style="font-size: 18px; font-weight: 700;">${premiumPrice} ₽</div>
2054                        <div style="font-size: 10px; opacity: 0.7; margin-top: 2px;">+15% от базовой</div>
2055                    </div>
2056                </div>
2057            `;
2058        }
2059
2060        html += `
2061            <div style="background: #10b981; padding: 5px 10px; border-radius: 6px; font-size: 13px; font-weight: 600; display: inline-block; margin-bottom: 10px;">
2062                ✨ ОПТИМАЛЬНАЯ ЦЕНА
2063            </div>
2064            
2065            <table style="width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 14px;">
2066                <thead>
2067                    <tr style="border-bottom: 2px solid rgba(255,255,255,0.3);">
2068                        <th style="text-align: left; padding: 6px; font-size: 14px; opacity: 0.9;">Показатель</th>
2069                        <th style="text-align: right; padding: 6px; font-size: 14px; opacity: 0.9;">Текущая</th>
2070                        <th style="text-align: right; padding: 6px; font-size: 14px; opacity: 0.9;">Рекомендуемая</th>
2071                        <th style="text-align: right; padding: 6px; font-size: 14px; opacity: 0.9;">Δ</th>
2072                    </tr>
2073                </thead>
2074                <tbody>
2075                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2076                        <td style="padding: 8px 6px; font-size: 14px;">Цена реализации</td>
2077                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentPrice} ₽</td>
2078                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2079                            ${optimal.price}2080                            <span style="color: ${priceChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2081                                (${priceChange >= 0 ? '+' : ''}${priceChange}%)
2082                            </span>
2083                        </td>
2084                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${priceDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2085                            ${priceDiff >= 0 ? '+' : ''}${priceDiff}2086                        </td>
2087                    </tr>
2088                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2089                        <td style="padding: 8px 6px; font-size: 14px;">Фактическая цена</td>
2090                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${Math.round(currentActualPrice)} ₽</td>
2091                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2092                            ${Math.round(optimal.actualPrice)}2093                            <span style="color: ${actualPriceChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2094                                (${actualPriceChange >= 0 ? '+' : ''}${actualPriceChange}%)
2095                            </span>
2096                        </td>
2097                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${actualPriceDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2098                            ${actualPriceDiff >= 0 ? '+' : ''}${actualPriceDiff}2099                        </td>
2100                    </tr>
2101                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2102                        <td style="padding: 8px 6px; font-size: 14px;">Прибыль/день</td>
2103                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDailyProfit} ₽</td>
2104                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2105                            ${optimal.estimatedDailyProfit}2106                            <span style="color: ${profitChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2107                                (${profitChange >= 0 ? '+' : ''}${profitChange}%)
2108                            </span>
2109                        </td>
2110                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${profitDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2111                            ${profitDiff >= 0 ? '+' : ''}${profitDiff}2112                        </td>
2113                    </tr>
2114                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2115                        <td style="padding: 8px 6px; font-size: 14px;">Выручка/день</td>
2116                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDailyRevenue} ₽</td>
2117                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2118                            ${optimalDailyRevenue}2119                            <span style="color: ${revenueChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2120                                (${revenueChange >= 0 ? '+' : ''}${revenueChange}%)
2121                            </span>
2122                        </td>
2123                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${revenueDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2124                            ${revenueDiff >= 0 ? '+' : ''}${revenueDiff}2125                        </td>
2126                    </tr>
2127                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2128                        <td style="padding: 8px 6px; font-size: 14px;">Продажи/день</td>
2129                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDailySales.toFixed(1)} шт</td>
2130                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2131                            ${optimal.estimatedDailySales} шт 
2132                            <span style="color: ${salesChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2133                                (${salesChange >= 0 ? '+' : ''}${salesChange}%)
2134                            </span>
2135                        </td>
2136                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${salesDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2137                            ${salesDiff >= 0 ? '+' : ''}${salesDiff} шт
2138                        </td>
2139                    </tr>
2140                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2141                        <td style="padding: 8px 6px; font-size: 14px;">Маржа %</td>
2142                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentMargin}%</td>
2143                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2144                            ${optimal.profitMargin}% 
2145                            <span style="color: ${marginChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2146                                (${marginChange >= 0 ? '+' : ''}${marginChange}%)
2147                            </span>
2148                        </td>
2149                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${marginChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2150                            ${marginChange >= 0 ? '+' : ''}${marginChange}%
2151                        </td>
2152                    </tr>
2153                    <tr style="border-bottom: 1px solid rgba(255,255,255,0.1);">
2154                        <td style="padding: 8px 6px; font-size: 14px;">Прибыль/шт</td>
2155                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentProfitPerUnit} ₽</td>
2156                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2157                            ${optimalProfitPerUnit}2158                            <span style="color: ${profitPerUnitChange >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2159                                (${profitPerUnitChange >= 0 ? '+' : ''}${profitPerUnitChange}%)
2160                            </span>
2161                        </td>
2162                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${profitPerUnitDiff >= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2163                            ${profitPerUnitDiff >= 0 ? '+' : ''}${profitPerUnitDiff}2164                        </td>
2165                    </tr>
2166                    <tr>
2167                        <td style="padding: 8px 6px; font-size: 14px;">Комиссия %</td>
2168                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentCommissionPercent}%</td>
2169                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2170                            ${optimalCommissionPercent}%
2171                            <span style="color: ${commissionPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2172                                (${commissionPercentChange >= 0 ? '+' : ''}${commissionPercentChange}%)
2173                            </span>
2174                        </td>
2175                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${commissionPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2176                            ${commissionPercentChange >= 0 ? '+' : ''}${commissionPercentChange}%
2177                        </td>
2178                    </tr>
2179                    <tr>
2180                        <td style="padding: 8px 6px; font-size: 14px;">Доставка %</td>
2181                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDeliveryPercent}%</td>
2182                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2183                            ${optimalDeliveryPercent}%
2184                            <span style="color: ${deliveryPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2185                                (${deliveryPercentChange >= 0 ? '+' : ''}${deliveryPercentChange}%)
2186                            </span>
2187                        </td>
2188                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${deliveryPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2189                            ${deliveryPercentChange >= 0 ? '+' : ''}${deliveryPercentChange}%
2190                        </td>
2191                    </tr>
2192                    <tr>
2193                        <td style="padding: 8px 6px; font-size: 14px;">Себестоимость %</td>
2194                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentCostPercent}%</td>
2195                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2196                            ${optimalCostPercent}%
2197                            <span style="color: ${costPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2198                                (${costPercentChange >= 0 ? '+' : ''}${costPercentChange}%)
2199                            </span>
2200                        </td>
2201                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${costPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2202                            ${costPercentChange >= 0 ? '+' : ''}${costPercentChange}%
2203                        </td>
2204                    </tr>
2205                    <tr>
2206                        <td style="padding: 8px 6px; font-size: 14px;">ДРР %</td>
2207                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">${currentDrrPercent}%</td>
2208                        <td style="padding: 8px 6px; text-align: right; font-weight: 600;">
2209                            ${optimalDrrPercent}%
2210                            <span style="color: ${drrPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px; font-weight: 700; margin-left: 4px;">
2211                                (${drrPercentChange >= 0 ? '+' : ''}${drrPercentChange}%)
2212                            </span>
2213                        </td>
2214                        <td style="padding: 8px 6px; text-align: right; font-weight: 600; color: ${drrPercentChange <= 0 ? '#10b981' : '#ef4444'}; font-size: 13px;">
2215                            ${drrPercentChange >= 0 ? '+' : ''}${drrPercentChange}%
2216                        </td>
2217                    </tr>
2218                </tbody>
2219            </table>
2220        `;
2221
2222        if (alternatives && alternatives.length > 0) {
2223            html += `
2224                <div style="margin-top: 12px; padding: 8px; background: rgba(255,255,255,0.1); border-radius: 6px; font-size: 12px; opacity: 0.8;">
2225                    💡 Анализ: ${allResults.length} вариантов цен. Уверенность: ${Math.round(optimal.confidence * 100)}%
2226                </div>
2227            `;
2228        }
2229
2230        resultsContent.innerHTML = html;
2231        resultsDiv.style.display = 'block';
2232        
2233        setTimeout(() => createPriceChart(optimization), 100);
2234    }
2235
2236    // Create price analysis chart
2237    function createPriceChart(optimization) {
2238        const oldChart = document.getElementById('price-analysis-chart');
2239        if (oldChart) {
2240            oldChart.parentElement.remove();
2241        }
2242        
2243        const canvas = document.createElement('canvas');
2244        canvas.id = 'price-analysis-chart';
2245        canvas.style.cssText = 'width: 100% !important; height: 250px !important;';
2246        
2247        const chartContainer = document.createElement('div');
2248        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;';
2249        chartContainer.innerHTML = `
2250            <div style="font-size: 14px; margin-bottom: 8px; opacity: 0.9; font-weight: 600;">
2251                📈 График зависимости от цены
2252            </div>
2253        `;
2254        chartContainer.appendChild(canvas);
2255        
2256        const resultsContent = document.getElementById('results-content');
2257        resultsContent.appendChild(chartContainer);
2258        
2259        const sortedResults = [...optimization.allResults].sort((a, b) => a.price - b.price);
2260        const prices = sortedResults.map(r => r.price);
2261        const sales = sortedResults.map(r => r.estimatedDailySales);
2262        const revenue = sortedResults.map(r => Math.round(r.price * r.estimatedDailySales));
2263        const profit = sortedResults.map(r => r.estimatedDailyProfit);
2264        
2265        const ctx = canvas.getContext('2d');
2266        window.priceAnalysisChart = new Chart(ctx, {
2267            type: 'line',
2268            data: {
2269                labels: prices,
2270                datasets: [
2271                    {
2272                        label: 'Продажи (шт/д)',
2273                        data: sales,
2274                        borderColor: '#10b981',
2275                        backgroundColor: 'rgba(16, 185, 129, 0.1)',
2276                        yAxisID: 'y',
2277                        tension: 0.4,
2278                        borderWidth: 2
2279                    },
2280                    {
2281                        label: 'Выручка (₽/д)',
2282                        data: revenue,
2283                        borderColor: '#f59e0b',
2284                        backgroundColor: 'rgba(245, 158, 11, 0.1)',
2285                        yAxisID: 'y1',
2286                        tension: 0.4,
2287                        borderWidth: 2
2288                    },
2289                    {
2290                        label: 'Прибыль (₽/д)',
2291                        data: profit,
2292                        borderColor: '#ef4444',
2293                        backgroundColor: 'rgba(239, 68, 68, 0.1)',
2294                        yAxisID: 'y1',
2295                        tension: 0.4,
2296                        borderWidth: 3
2297                    }
2298                ]
2299            },
2300            options: {
2301                responsive: true,
2302                maintainAspectRatio: true,
2303                aspectRatio: 2.2,
2304                interaction: {
2305                    mode: 'index',
2306                    intersect: false,
2307                },
2308                plugins: {
2309                    legend: {
2310                        position: 'top',
2311                        labels: {
2312                            usePointStyle: true,
2313                            padding: 12,
2314                            font: { size: 12 },
2315                            color: 'white',
2316                            boxWidth: 8,
2317                            boxHeight: 8
2318                        }
2319                    },
2320                    tooltip: {
2321                        backgroundColor: 'rgba(0, 0, 0, 0.8)',
2322                        padding: 10,
2323                        titleFont: { size: 13 },
2324                        bodyFont: { size: 12 },
2325                        callbacks: {
2326                            title: function(context) {
2327                                return 'Цена: ' + context[0].label + ' ₽';
2328                            },
2329                            label: function(context) {
2330                                let label = context.dataset.label || '';
2331                                if (label) {
2332                                    label += ': ';
2333                                }
2334                                if (context.parsed.y !== null) {
2335                                    if (label.includes('шт')) {
2336                                        label += context.parsed.y.toFixed(1);
2337                                    } else {
2338                                        label += Math.round(context.parsed.y);
2339                                    }
2340                                }
2341                                return label;
2342                            }
2343                        }
2344                    }
2345                },
2346                scales: {
2347                    x: {
2348                        title: {
2349                            display: true,
2350                            text: 'Цена (₽)',
2351                            font: { size: 12, weight: 'bold' },
2352                            color: 'white'
2353                        },
2354                        ticks: {
2355                            maxTicksLimit: 8,
2356                            font: { size: 11 },
2357                            color: 'rgba(255, 255, 255, 0.8)'
2358                        },
2359                        grid: {
2360                            color: 'rgba(255, 255, 255, 0.1)'
2361                        }
2362                    },
2363                    y: {
2364                        type: 'linear',
2365                        display: true,
2366                        position: 'left',
2367                        title: {
2368                            display: true,
2369                            text: 'Продажи',
2370                            color: '#10b981',
2371                            font: { size: 12 }
2372                        },
2373                        ticks: {
2374                            font: { size: 11 },
2375                            color: 'rgba(255, 255, 255, 0.8)'
2376                        },
2377                        grid: {
2378                            color: 'rgba(255, 255, 255, 0.1)'
2379                        }
2380                    },
2381                    y1: {
2382                        type: 'linear',
2383                        display: true,
2384                        position: 'right',
2385                        title: {
2386                            display: true,
2387                            text: 'Выручка/Прибыль',
2388                            color: '#f59e0b',
2389                            font: { size: 12 }
2390                        },
2391                        grid: {
2392                            drawOnChartArea: false,
2393                        },
2394                        ticks: {
2395                            font: { size: 11 },
2396                            color: 'rgba(255, 255, 255, 0.8)'
2397                        }
2398                    }
2399                }
2400            }
2401        });
2402        
2403        console.log('График создан успешно');
2404    }
2405
2406    // Wait for MP Stats widget to load
2407    function waitForMPStats() {
2408        console.log('Waiting for MP Stats widget and page hydration...');
2409        
2410        let checkCount = 0;
2411        const maxChecks = 30;
2412        
2413        const checkInterval = setInterval(() => {
2414            checkCount++;
2415            console.log(`Check ${checkCount}/${maxChecks} for MP Stats widget...`);
2416            
2417            const mpsWidget = document.querySelector('.mps-sidebar');
2418            const chartSvg = mpsWidget ? mpsWidget.querySelector('.vue-apexcharts svg') : null;
2419            const bars = chartSvg ? chartSvg.querySelectorAll('.apexcharts-bar-area') : null;
2420            
2421            if (mpsWidget && chartSvg && bars && bars.length > 0) {
2422                console.log(`MP Stats widget and chart found with ${bars.length} bars, waiting for hydration to complete...`);
2423                clearInterval(checkInterval);
2424                setTimeout(() => {
2425                    console.log('Creating analysis widget now...');
2426                    createAnalysisWidget();
2427                }, 3000);
2428            } else if (checkCount >= maxChecks) {
2429                clearInterval(checkInterval);
2430                console.log('Stopped waiting for MP Stats widget - timeout reached');
2431            }
2432        }, 1000);
2433    }
2434
2435    // Initialize
2436    function init() {
2437        console.log('OZON Price Optimizer initialized (v2.0.1)');
2438        console.log('Current URL:', window.location.href);
2439        
2440        // Check if we're on a search page and need to extract competitors
2441        if (window.location.href.includes('/search/') || window.location.href.includes('/category/')) {
2442            console.log('Search/category page detected, checking for competitor extraction...');
2443            extractCompetitorsInSearchPage();
2444            return;
2445        }
2446        
2447        const productId = getProductId();
2448        if (!productId) {
2449            console.log('Not a product page, skipping...');
2450            return;
2451        }
2452
2453        console.log('Product page detected, waiting for MP Stats widget...');
2454        
2455        if (document.readyState === 'loading') {
2456            document.addEventListener('DOMContentLoaded', waitForMPStats);
2457        } else {
2458            waitForMPStats();
2459        }
2460    }
2461
2462    init();
2463})();
OZON Price Optimizer with Competitor Analysis | Robomonkey