File size: 53,448 Bytes
fa57651
 
1843932
 
fa57651
1843932
 
 
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
fa57651
1843932
 
fa57651
1843932
 
 
fa57651
1843932
 
 
 
fa57651
1843932
fa57651
 
 
1843932
 
fa57651
1843932
fa57651
1843932
 
fa57651
1843932
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
 
fa57651
1843932
 
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
 
 
 
 
fa57651
 
1843932
 
 
fa57651
1843932
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
fa57651
1843932
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
 
1843932
 
 
 
fa57651
1843932
 
 
 
 
 
 
fa57651
1843932
fa57651
1843932
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
 
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
 
1843932
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
 
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa57651
1843932
 
 
 
 
 
 
 
 
 
 
 
fa57651
 
1843932
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
import streamlit as st
import pandas as pd
import ee
import geemap.foliumap as geemap
import folium
import json
import datetime
import plotly.express as px
import os
from io import BytesIO
import requests # Needed for getThumbUrl download
import traceback
from streamlit_folium import st_folium
import base64
import google.generativeai as genai # Added for Gemini

# --- Custom CSS ---
st.set_page_config(
    page_title="سامانه پایش هوشمند نیشکر",
    page_icon="🌾",
    layout="wide"
)

# Custom CSS for Persian text alignment and professional styling
st.markdown("""
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap');
        
        /* Main container */
        .main {
            font-family: 'Vazirmatn', sans-serif;
        }
        
        /* Headers */
        h1, h2, h3 {
            font-family: 'Vazirmatn', sans-serif;
            color: #2c3e50;
            text-align: right;
        }
        
        /* Metrics */
        .css-1xarl3l { /* Streamlit's default metric class, adjust if needed */
            font-family: 'Vazirmatn', sans-serif;
            background-color: #f8f9fa;
            border-radius: 10px;
            padding: 1rem;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        
        /* Tabs */
        .stTabs [data-baseweb="tab-list"] {
            gap: 2px;
            direction: rtl;
        }
        
        .stTabs [data-baseweb="tab"] {
            height: 50px;
            padding: 10px 20px;
            background-color: #f8f9fa;
            border-radius: 5px 5px 0 0;
            font-family: 'Vazirmatn', sans-serif;
            font-weight: 600;
        }
        
        /* Tables */
        .dataframe {
            font-family: 'Vazirmatn', sans-serif;
            text-align: right;
        }
        
        /* Sidebar */
        .css-1d391kg { /* Streamlit's default sidebar class, adjust if needed */
            font-family: 'Vazirmatn', sans-serif;
            direction: rtl;
        }
        
        /* Custom status badges */
        .status-badge {
            padding: 4px 8px;
            border-radius: 15px;
            font-size: 0.8em;
            font-weight: bold;
        }
        .status-positive {
            background-color: #d4edda;
            color: #155724;
        }
        .status-neutral {
            background-color: #fff3cd;
            color: #856404;
        }
        .status-negative {
            background-color: #f8d7da;
            color: #721c24;
        }
    </style>
""", unsafe_allow_html=True)

# --- Configuration ---
APP_TITLE = "سامانه پایش هوشمند نیشکر"
APP_SUBTITLE = "مطالعات کاربردی شرکت کشت و صنعت دهخدا"
INITIAL_LAT = 31.534442
INITIAL_LON = 48.724416
INITIAL_ZOOM = 12

# --- File Paths (Relative to the script location in Hugging Face) ---
CSV_FILE_PATH = 'cleaned_output.csv'
SERVICE_ACCOUNT_FILE = 'ee-esmaeilkiani13877-cfdea6eaf411 (4).json'

# --- GEE Authentication ---
@st.cache_resource # Cache the GEE initialization
def initialize_gee():
    """Initializes Google Earth Engine using the Service Account."""
    try:
        if not os.path.exists(SERVICE_ACCOUNT_FILE):
            st.error(f"خطا: فایل Service Account در مسیر '{SERVICE_ACCOUNT_FILE}' یافت نشد.")
            st.stop()
        credentials = ee.ServiceAccountCredentials(None, key_file=SERVICE_ACCOUNT_FILE)
        ee.Initialize(credentials=credentials, opt_url='https://earthengine-highvolume.googleapis.com')
        print("GEE Initialized Successfully using Service Account.")
        return True
    except ee.EEException as e:
        st.error(f"خطا در اتصال به Google Earth Engine: {e}")
        st.error("لطفاً از صحت فایل Service Account و فعال بودن آن در پروژه GEE اطمینان حاصل کنید.")
        st.stop()
    except Exception as e:
        st.error(f"خطای غیرمنتظره هنگام اتصال به GEE: {e}")
        st.stop()


# --- Load Farm Data ---
@st.cache_data(show_spinner="در حال بارگذاری داده‌های مزارع...")
def load_farm_data():
    """Loads farm data from GEE FeatureCollection."""
    try:
        # Load Shapefile from GEE Assets
        fc = ee.FeatureCollection('projects/ee-esmaeilkiani13877/assets/Croplogging-Farm')
        
        # Extract features and properties
        features = fc.getInfo()['features']
        
        farm_data = []
        for f in features:
            props = f['properties']
            geom = f['geometry']
            
            # Extract coordinates (assuming Point geometry)
            # Handle cases where geometry might be missing or not a Point
            lon, lat = (None, None)
            if geom and geom.get('type') == 'Point' and geom.get('coordinates'):
                coords = geom['coordinates']
                if len(coords) == 2:
                    lon, lat = coords[0], coords[1]
            
            farm_data.append({
                'مزرعه': props.get('farm', 'N/A'),
                'طول جغرافیایی': lon,
                'عرض جغرافیایی': lat,
                'روزهای هفته': props.get('Day', 'N/A'), # Assuming 'Day' field exists
                'مساحت': props.get('Area', 0), # Assuming 'Area' field exists
                'واریته': props.get('Variety', 'N/A'), # Assuming 'Variety' field exists
                'اداره': props.get('edare', 'N/A'), # Assuming 'edare' field exists
                'کانال': props.get('group', 'N/A'), # Assuming 'group' field exists
                'سن': props.get('Age', 'N/A'), # Assuming 'Age' field exists
                'coordinates_missing': lon is None or lat is None
            })
        
        df = pd.DataFrame(farm_data)
        
        # Data cleaning
        required_cols = ['مزرعه', 'طول جغرافیایی', 'عرض جغرافیایی', 'روزهای هفته', 'coordinates_missing']
        if not all(col in df.columns for col in required_cols):
            st.error(f"❌ داده‌های بارگذاری شده از GEE شامل ستون‌های ضروری نیست: {', '.join(required_cols)}")
            # Attempt to create missing columns with default values if appropriate
            for col in required_cols:
                if col not in df.columns:
                    if col == 'coordinates_missing':
                        df[col] = True # Default to True if other coordinate columns are missing
                    elif col in ['طول جغرافیایی', 'عرض جغرافیایی']:
                        df[col] = pd.NA # Use pandas NA for numeric missing
                    else:
                        df[col] = 'N/A' # Default string for other missing text columns
            # Re-check after attempting to fix
            if not all(col in df.columns for col in required_cols):
                 st.error("بعضی از ستون‌های ضروری پس از تلاش برای ایجاد پیش‌فرض، هنوز موجود نیستند.")
                 return None


        df['طول جغرافیایی'] = pd.to_numeric(df['طول جغرافیایی'], errors='coerce')
        df['عرض جغرافیایی'] = pd.to_numeric(df['عرض جغرافیایی'], errors='coerce')
        df['coordinates_missing'] = df['coordinates_missing'].fillna(True).astype(bool) # Default to True if missing
        
        # Ensure 'روزهای هفته' is string and stripped, handle potential NaN before astype(str)
        df['روزهای هفته'] = df['روزهای هفته'].fillna('N/A').astype(str).str.strip()

        df = df.dropna(subset=['طول جغرافیایی', 'عرض جغرافیایی']) # Keep this
        df = df[~df['coordinates_missing']] # Keep this
        
        if df.empty:
            st.warning("⚠️ داده معتبری برای مزارع یافت نشد (پس از حذف رکوردهای بدون مختصات یا با مختصات نامعتبر از GEE).")
            return None

        st.success(f"✅ داده‌های {len(df)} مزرعه با موفقیت از Google Earth Engine بارگذاری شد.")
        return df
        
    except ee.EEException as e:
        st.error(f"خطا در بارگذاری داده از GEE: {e}")
        st.error("لطفاً از صحت نام Asset در GEE و دسترسی به آن اطمینان حاصل کنید.")
        return None
    except Exception as e:
        st.error(f"❌ خطا در پردازش داده‌های مزارع از GEE: {e}")
        st.error(traceback.format_exc())
        return None

# Initialize GEE and Load Data
if initialize_gee():
    farm_data_df = load_farm_data()
else:
    st.error("❌ امکان ادامه کار بدون اتصال به Google Earth Engine وجود ندارد.")
    st.stop()

if farm_data_df is None:
    st.error("❌ امکان ادامه کار بدون داده‌های مزارع وجود ندارد.")
    st.stop()

# ==============================================================================
# Gemini API Configuration
# ==============================================================================
st.sidebar.subheader("✨ تنظیمات هوش مصنوعی Gemini")
GEMINI_API_KEY = st.sidebar.text_input("🔑 کلید API جمینای خود را وارد کنید:", type="password", help="برای استفاده از قابلیت‌های هوشمند، کلید API خود را از Google AI Studio دریافت و وارد کنید.")

gemini_model = None
if GEMINI_API_KEY:
    try:
        genai.configure(api_key=GEMINI_API_KEY)
        gemini_model = genai.GenerativeModel('gemini-1.5-flash-latest') # Using a recent model
        st.sidebar.success("✅ اتصال به Gemini برقرار شد.")
    except Exception as e:
        st.sidebar.error(f"خطا در اتصال به Gemini: {e}")
        gemini_model = None
else:
    st.sidebar.info("قابلیت‌های هوشمند Gemini با وارد کردن کلید API فعال می‌شوند.")

def ask_gemini(prompt_text, temperature=0.7, top_p=1.0, top_k=40):
    """Sends a prompt to Gemini and returns the response."""
    if not gemini_model:
        return "خطا: مدل Gemini مقداردهی اولیه نشده است. لطفاً کلید API را بررسی کنید."
    try:
        # Configuration for generation
        generation_config = genai.types.GenerationConfig(
            temperature=temperature,
            top_p=top_p,
            top_k=top_k,
            max_output_tokens=2048 # Adjust as needed
        )
        response = gemini_model.generate_content(prompt_text, generation_config=generation_config)
        return response.text
    except Exception as e:
        return f"خطا در ارتباط با Gemini API: {e}\n{traceback.format_exc()}"


# ==============================================================================
# Sidebar Filters
# ==============================================================================
st.sidebar.header("تنظیمات نمایش")

available_days = sorted(farm_data_df['روزهای هفته'].unique())
selected_day = st.sidebar.selectbox(
    "📅 روز هفته را انتخاب کنید:",
    options=available_days,
    index=0,
    help="داده‌های مزارع بر اساس این روز فیلتر می‌شوند."
)

filtered_farms_df = farm_data_df[farm_data_df['روزهای هفته'] == selected_day].copy()

if filtered_farms_df.empty:
    st.warning(f"⚠️ هیچ مزرعه‌ای برای روز '{selected_day}' یافت نشد.")
    st.stop()

available_farms = sorted(filtered_farms_df['مزرعه'].unique())
farm_options = ["همه مزارع"] + available_farms
selected_farm_name = st.sidebar.selectbox(
    "🌾 مزرعه مورد نظر را انتخاب کنید:",
    options=farm_options,
    index=0,
    help="مزرعه‌ای که می‌خواهید جزئیات آن را ببینید یا 'همه مزارع' برای نمایش کلی."
)

index_options = {
    "NDVI": "شاخص پوشش گیاهی تفاضلی نرمال شده",
    "EVI": "شاخص پوشش گیاهی بهبود یافته",
    "NDMI": "شاخص رطوبت تفاضلی نرمال شده",
    "LAI": "شاخص سطح برگ (تخمینی)",
    "MSI": "شاخص تنش رطوبتی",
    "CVI": "شاخص کلروفیل (تخمینی)",
}
selected_index = st.sidebar.selectbox(
    "📈 شاخص مورد نظر برای نمایش روی نقشه:",
    options=list(index_options.keys()),
    format_func=lambda x: f"{x} ({index_options[x]})",
    index=0
)

today = datetime.date.today()
persian_to_weekday = {
    "شنبه": 5, "یکشنبه": 6, "دوشنبه": 0, "سه شنبه": 1,
    "چهارشنبه": 2, "پنجشنبه": 3, "جمعه": 4,
}
try:
    target_weekday = persian_to_weekday[selected_day]
    days_ago = (today.weekday() - target_weekday + 7) % 7
    end_date_current = today - datetime.timedelta(days=days_ago if days_ago !=0 else 0) # Corrected logic for today
    if today.weekday() == target_weekday: # If today is the selected day
        end_date_current = today
    else: # Find the most recent past selected_day
        days_to_subtract = (today.weekday() - target_weekday + 7) % 7
        end_date_current = today - datetime.timedelta(days=days_to_subtract)


    start_date_current = end_date_current - datetime.timedelta(days=6)
    end_date_previous = start_date_current - datetime.timedelta(days=1)
    start_date_previous = end_date_previous - datetime.timedelta(days=6)

    start_date_current_str = start_date_current.strftime('%Y-%m-%d')
    end_date_current_str = end_date_current.strftime('%Y-%m-%d')
    start_date_previous_str = start_date_previous.strftime('%Y-%m-%d')
    end_date_previous_str = end_date_previous.strftime('%Y-%m-%d')

    st.sidebar.info(f"بازه زمانی فعلی: {start_date_current_str} تا {end_date_current_str}")
    st.sidebar.info(f"بازه زمانی قبلی: {start_date_previous_str} تا {end_date_previous_str}")

except KeyError:
    st.sidebar.error(f"نام روز هفته '{selected_day}' قابل شناسایی نیست.")
    st.stop()
except Exception as e:
    st.sidebar.error(f"خطا در محاسبه بازه زمانی: {e}")
    st.stop()

# ==============================================================================
# Google Earth Engine Functions
# ==============================================================================
def maskS2clouds(image):
    qa = image.select('QA60')
    cloudBitMask = 1 << 10
    cirrusBitMask = 1 << 11
    mask = qa.bitwiseAnd(cloudBitMask).eq(0).And(qa.bitwiseAnd(cirrusBitMask).eq(0))
    scl = image.select('SCL')
    good_quality = scl.remap([4, 5, 6, 7, 11], [1, 1, 1, 1, 1], 0)
    opticalBands = image.select('B.*').multiply(0.0001)
    return image.addBands(opticalBands, None, True).updateMask(mask).updateMask(good_quality)

def add_indices(image):
    ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI')
    evi = image.expression(
        '2.5 * (NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1)',
        {'NIR': image.select('B8'), 'RED': image.select('B4'), 'BLUE': image.select('B2')}
    ).rename('EVI')
    ndmi = image.normalizedDifference(['B8', 'B11']).rename('NDMI')
    msi = image.expression('SWIR1 / NIR', {'SWIR1': image.select('B11'), 'NIR': image.select('B8')}).rename('MSI')
    lai = ndvi.multiply(3.5).rename('LAI')
    green_safe = image.select('B3').max(ee.Image(0.0001))
    cvi = image.expression('(NIR / GREEN) * (RED / GREEN)',
        {'NIR': image.select('B8'), 'GREEN': green_safe, 'RED': image.select('B4')}
    ).rename('CVI')
    return image.addBands([ndvi, evi, ndmi, msi, lai, cvi])

@st.cache_data(show_spinner="در حال پردازش تصاویر ماهواره‌ای...", persist=True)
def get_processed_image(_geometry, start_date, end_date, index_name):
    try:
        s2_sr_col = (ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
                     .filterBounds(_geometry)
                     .filterDate(start_date, end_date)
                     .map(maskS2clouds))
        count = s2_sr_col.size().getInfo()
        if count == 0:
            return None, f"No cloud-free Sentinel-2 images found for {start_date} to {end_date}."
        indexed_col = s2_sr_col.map(add_indices)
        median_image = indexed_col.median()
        output_image = median_image.select(index_name)
        return output_image, None
    except ee.EEException as e:
        error_message = f"خطای Google Earth Engine: {e}"
        try:
            error_details = e.args[0] if e.args else str(e)
            if isinstance(error_details, str) and 'computation timed out' in error_details.lower():
                 error_message += "\n(احتمالاً به دلیل حجم بالای پردازش یا بازه زمانی طولانی)"
            elif isinstance(error_details, str) and 'user memory limit exceeded' in error_details.lower():
                 error_message += "\n(احتمالاً به دلیل پردازش منطقه بزرگ یا عملیات پیچیده)"
        except Exception: pass
        return None, error_message
    except Exception as e:
        return None, f"خطای ناشناخته در پردازش GEE: {e}\n{traceback.format_exc()}"

@st.cache_data(show_spinner="در حال دریافت سری زمانی شاخص...", persist=True)
def get_index_time_series(_point_geom, index_name, start_date='2023-01-01', end_date=today.strftime('%Y-%m-%d')):
    try:
        s2_sr_col = (ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')
                     .filterBounds(_point_geom)
                     .filterDate(start_date, end_date)
                     .map(maskS2clouds)
                     .map(add_indices))
        def extract_value(image):
            value = image.reduceRegion(
                reducer=ee.Reducer.first(), geometry=_point_geom, scale=10
            ).get(index_name)
            return ee.Feature(None, {'date': image.date().format('YYYY-MM-dd'), index_name: value})
        ts_features = s2_sr_col.map(extract_value).filter(ee.Filter.notNull([index_name]))
        ts_info = ts_features.getInfo()['features']
        if not ts_info:
            return pd.DataFrame(columns=['date', index_name]), "داده‌ای برای سری زمانی یافت نشد."
        ts_data = [{'date': f['properties']['date'], index_name: f['properties'][index_name]} for f in ts_info]
        ts_df = pd.DataFrame(ts_data)
        ts_df['date'] = pd.to_datetime(ts_df['date'])
        ts_df = ts_df.sort_values('date').set_index('date')
        return ts_df, None
    except ee.EEException as e:
        return pd.DataFrame(columns=['date', index_name]), f"خطای GEE در دریافت سری زمانی: {e}"
    except Exception as e:
        return pd.DataFrame(columns=['date', index_name]), f"خطای ناشناخته در دریافت سری زمانی: {e}\n{traceback.format_exc()}"

# ==============================================================================
# Main Panel Display
# ==============================================================================
tab1, tab2, tab3 = st.tabs(["📊 داشبورد اصلی", "🗺️ نقشه و نمودارها", "💡 تحلیل هوشمند با Gemini"])

with tab1:
    st.header(APP_TITLE)
    st.subheader(APP_SUBTITLE)

    selected_farm_details = None
    selected_farm_geom = None
    lat, lon = INITIAL_LAT, INITIAL_LON # Default values

    if selected_farm_name == "همه مزارع":
        min_lon_df, min_lat_df = filtered_farms_df['طول جغرافیایی'].min(), filtered_farms_df['عرض جغرافیایی'].min()
        max_lon_df, max_lat_df = filtered_farms_df['طول جغرافیایی'].max(), filtered_farms_df['عرض جغرافیایی'].max()
        selected_farm_geom = ee.Geometry.Rectangle([min_lon_df, min_lat_df, max_lon_df, max_lat_df])
        st.subheader(f"نمایش کلی مزارع برای روز: {selected_day}")
        st.info(f"تعداد مزارع در این روز: {len(filtered_farms_df)}")
    else:
        selected_farm_details = filtered_farms_df[filtered_farms_df['مزرعه'] == selected_farm_name].iloc[0]
        lat = selected_farm_details['عرض جغرافیایی']
        lon = selected_farm_details['طول جغرافیایی']
        selected_farm_geom = ee.Geometry.Point([lon, lat])
        st.subheader(f"جزئیات مزرعه: {selected_farm_name} (روز: {selected_day})")
        details_cols = st.columns(3)
        with details_cols[0]:
            st.metric("مساحت داشت (هکتار)", f"{selected_farm_details.get('مساحت', 'N/A'):,.2f}" if pd.notna(selected_farm_details.get('مساحت')) else "N/A")
            st.metric("واریته", f"{selected_farm_details.get('واریته', 'N/A')}")
        with details_cols[1]:
            st.metric("کانال", f"{selected_farm_details.get('کانال', 'N/A')}")
            st.metric("سن", f"{selected_farm_details.get('سن', 'N/A')}")
        with details_cols[2]:
            st.metric("اداره", f"{selected_farm_details.get('اداره', 'N/A')}")
            st.metric("مختصات", f"{lat:.5f}, {lon:.5f}")

    st.markdown("---")
    st.subheader(f"📊 جدول رتبه‌بندی مزارع بر اساس {selected_index} (روز: {selected_day})")
    st.markdown("مقایسه مقادیر متوسط شاخص در هفته جاری با هفته قبل.")

    @st.cache_data(show_spinner=f"در حال محاسبه {selected_index} برای مزارع...", persist=True)
    def calculate_weekly_indices(_farms_df, index_name, start_curr, end_curr, start_prev, end_prev):
        results = []
        errors = []
        total_farms = len(_farms_df)
        progress_bar = st.progress(0)
        for i, (idx, farm) in enumerate(_farms_df.iterrows()):
            farm_name = farm['مزرعه']
            _lat = farm['عرض جغرافیایی']
            _lon = farm['طول جغرافیایی']
            point_geom = ee.Geometry.Point([_lon, _lat])
            def get_mean_value(start, end):
                try:
                    image, error = get_processed_image(point_geom, start, end, index_name)
                    if image:
                        mean_dict = image.reduceRegion(reducer=ee.Reducer.mean(), geometry=point_geom, scale=10).getInfo()
                        return mean_dict.get(index_name) if mean_dict else None, None
                    return None, error
                except Exception as e:
                     return None, f"خطا در محاسبه مقدار برای {farm_name} ({start}-{end}): {e}"
            current_val, err_curr = get_mean_value(start_curr, end_curr)
            if err_curr: errors.append(f"{farm_name} (هفته جاری): {err_curr}")
            previous_val, err_prev = get_mean_value(start_prev, end_prev)
            if err_prev: errors.append(f"{farm_name} (هفته قبل): {err_prev}")
            change = None
            if current_val is not None and previous_val is not None:
                try: change = current_val - previous_val
                except TypeError: change = None
            results.append({
                'مزرعه': farm_name, 'کانال': farm.get('کانال', 'N/A'), 'اداره': farm.get('اداره', 'N/A'),
                f'{index_name} (هفته جاری)': current_val, f'{index_name} (هفته قبل)': previous_val, 'تغییر': change
            })
            progress_bar.progress((i + 1) / total_farms)
        progress_bar.empty()
        return pd.DataFrame(results), errors

    ranking_df, calculation_errors = calculate_weekly_indices(
        filtered_farms_df, selected_index,
        start_date_current_str, end_date_current_str,
        start_date_previous_str, end_date_previous_str
    )

    if calculation_errors:
        st.warning("⚠️ برخی خطاها در حین محاسبه شاخص‌ها رخ داد:")
        for error in calculation_errors[:5]: st.caption(f"- {error}") # Show limited errors
        if len(calculation_errors) > 5: st.caption(f"... و {len(calculation_errors) - 5} خطای دیگر.")

    ranking_df_sorted = pd.DataFrame() # Initialize to avoid NameError if ranking_df is empty
    if not ranking_df.empty:
        ascending_sort = selected_index in ['MSI']
        ranking_df_sorted = ranking_df.sort_values(
            by=f'{selected_index} (هفته جاری)', ascending=ascending_sort, na_position='last'
        ).reset_index(drop=True)
        ranking_df_sorted.index = ranking_df_sorted.index + 1
        ranking_df_sorted.index.name = 'رتبه'

        def determine_status(row, index_name):
            if pd.isna(row['تغییر']) or pd.isna(row[f'{index_name} (هفته جاری)']) or pd.isna(row[f'{index_name} (هفته قبل)']):
                return "بدون داده"
            if index_name in ['NDVI', 'EVI', 'LAI', 'CVI']:
                if row['تغییر'] > 0.05: return "رشد مثبت"
                elif row['تغییر'] < -0.05: return "تنش/کاهش"
                else: return "ثابت"
            elif index_name in ['MSI', 'NDMI']: # NDMI was missing, MSI logic might need adjustment
                if row['تغییر'] < -0.05: return "بهبود" # Lower MSI/NDMI is better, so negative change is improvement
                elif row['تغییر'] > 0.05: return "تنش/بدتر شدن"
                else: return "ثابت"
            return "نامشخص"

        ranking_df_sorted['وضعیت'] = ranking_df_sorted.apply(lambda row: determine_status(row, selected_index), axis=1)
        cols_to_format = [f'{selected_index} (هفته جاری)', f'{selected_index} (هفته قبل)', 'تغییر']
        for col_format in cols_to_format:
            if col_format in ranking_df_sorted.columns:
                 ranking_df_sorted[col_format] = ranking_df_sorted[col_format].map(lambda x: f"{x:.3f}" if pd.notna(x) else "N/A")
        st.dataframe(ranking_df_sorted, use_container_width=True)

        st.subheader("📊 خلاصه وضعیت مزارع")
        status_counts = ranking_df_sorted['وضعیت'].value_counts()
        col1, col2, col3, col4 = st.columns(4)
        with col1:
            count_positive = status_counts.get("رشد مثبت", 0) + status_counts.get("بهبود", 0)
            st.metric("🟢 بهبود/رشد", count_positive)
        with col2:
            st.metric("⚪ ثابت", status_counts.get("ثابت", 0))
        with col3:
            count_negative = status_counts.get("تنش/کاهش", 0) + status_counts.get("تنش/بدتر شدن", 0)
            st.metric("🔴 تنش/کاهش", count_negative)
        with col4:
            st.metric("❔ بدون داده", status_counts.get("بدون داده", 0))

        st.info("""
        **توضیحات وضعیت:**
        - **🟢 رشد مثبت/بهبود**: مزارعی که نسبت به هفته قبل بهبود قابل توجهی داشته‌اند (افزایش در شاخص‌های مثبت مانند NDVI، یا کاهش در شاخص‌های تنش مانند MSI).
        - **⚪ ثابت**: مزارعی که تغییر معناداری نداشته‌اند.
        - **🔴 تنش/کاهش**: مزارعی که نسبت به هفته قبل وضعیت بدتری داشته‌اند.
        - **❔ بدون داده**: اطلاعات کافی برای ارزیابی وضعیت موجود نیست.
        """)

        csv_data = ranking_df_sorted.to_csv(index=True).encode('utf-8')
        st.download_button(
            label="📥 دانلود جدول رتبه‌بندی (CSV)", data=csv_data,
            file_name=f'ranking_{selected_index}_{selected_day}_{end_date_current_str}.csv', mime='text/csv',
        )
    else:
        st.info(f"داده‌ای برای جدول رتبه‌بندی بر اساس {selected_index} در این بازه زمانی یافت نشد.")

with tab2:
    st.subheader("🗺️ نقشه وضعیت مزارع")
    vis_params = {
        'NDVI': {'min': 0, 'max': 1, 'palette': ['red', 'yellow', 'green']},
        'EVI': {'min': 0, 'max': 1, 'palette': ['red', 'yellow', 'green']},
        'NDMI': {'min': -1, 'max': 1, 'palette': ['brown', 'white', 'blue']},
        'LAI': {'min': 0, 'max': 6, 'palette': ['white', 'lightgreen', 'darkgreen']},
        'MSI': {'min': 0, 'max': 3, 'palette': ['blue', 'white', 'brown']}, # Low MSI = high moisture (blue), High MSI = low moisture (brown)
        'CVI': {'min': 0, 'max': 20, 'palette': ['yellow', 'lightgreen', 'darkgreen']},
    }
    map_center_lat = lat if selected_farm_name != "همه مزارع" else INITIAL_LAT
    map_center_lon = lon if selected_farm_name != "همه مزارع" else INITIAL_LON
    initial_zoom_map = 14 if selected_farm_name != "همه مزارع" else INITIAL_ZOOM

    m = geemap.Map(location=[map_center_lat, map_center_lon], zoom=initial_zoom_map, add_google_map=False)
    m.add_basemap("HYBRID")

    if selected_farm_geom:
        gee_image_current, error_msg_current = get_processed_image(
            selected_farm_geom, start_date_current_str, end_date_current_str, selected_index
        )
        if gee_image_current:
            try:
                m.addLayer(
                    gee_image_current,
                    vis_params.get(selected_index, {'min': 0, 'max': 1, 'palette': ['red', 'yellow', 'green']}),
                    f"{selected_index} ({start_date_current_str} to {end_date_current_str})"
                )
                # Custom Legend
                legend_html_content = ""
                if selected_index in ['NDVI', 'EVI', 'LAI', 'CVI']:
                    legend_html_content = '<p style="margin: 0; color: red;">بحرانی/پایین</p><p style="margin: 0; color: yellow;">متوسط</p><p style="margin: 0; color: green;">سالم/بالا</p>'
                elif selected_index == 'NDMI': # NDMI: Blue for wet, brown for dry
                     legend_html_content = '<p style="margin: 0; color: brown;">خشک</p><p style="margin: 0; color: white;">متوسط</p><p style="margin: 0; color: blue;">مرطوب</p>'
                elif selected_index == 'MSI': # MSI: Brown for high stress (dry), Blue for low stress (wet)
                     legend_html_content = '<p style="margin: 0; color: blue;">رطوبت بالا / تنش کم</p><p style="margin: 0; color: white;">متوسط</p><p style="margin: 0; color: brown;">رطوبت پایین / تنش زیاد</p>'

                if legend_html_content:
                    legend_html = f'''
                    <div style="position: fixed; bottom: 50px; left: 10px; z-index: 1000; background-color: white; padding: 10px; border: 1px solid grey; border-radius: 5px; font-family: Vazirmatn, sans-serif;">
                        <p style="margin: 0; font-weight: bold;">راهنمای {selected_index}</p>
                        {legend_html_content}
                    </div>
                    '''
                    m.get_root().html.add_child(folium.Element(legend_html))

                if selected_farm_name == "همه مزارع":
                     for idx_farm, farm_row in filtered_farms_df.iterrows():
                         folium.Marker(
                             location=[farm_row['عرض جغرافیایی'], farm_row['طول جغرافیایی']],
                             popup=f"مزرعه: {farm_row['مزرعه']}<br>کانال: {farm_row['کانال']}<br>اداره: {farm_row['اداره']}",
                             tooltip=farm_row['مزرعه'], icon=folium.Icon(color='blue', icon='info-sign')
                         ).add_to(m)
                     m.center_object(selected_farm_geom, zoom=INITIAL_ZOOM)
                else:
                     folium.Marker(
                         location=[lat, lon], tooltip=selected_farm_name,
                         icon=folium.Icon(color='red', icon='star')
                     ).add_to(m)
                     m.center_object(selected_farm_geom, zoom=14)
                m.add_layer_control()
            except Exception as map_err:
                st.error(f"خطا در افزودن لایه به نقشه: {map_err}\n{traceback.format_exc()}")
        else:
            st.warning(f"تصویری برای نمایش روی نقشه یافت نشد. {error_msg_current}")
        st_folium(m, width=None, height=500, use_container_width=True)
        st.caption("برای مشاهده جزئیات روی مارکرها کلیک کنید. از کنترل لایه‌ها برای تغییر نقشه پایه استفاده کنید.")
    else:
        st.warning("هندسه مزرعه برای نمایش نقشه انتخاب نشده است.")


    st.markdown("---")
    st.subheader(f"📈 نمودار روند زمانی شاخص {selected_index}")
    if selected_farm_name == "همه مزارع":
        st.info("لطفاً یک مزرعه خاص را از پنل کناری انتخاب کنید تا نمودار روند زمانی آن نمایش داده شود.")
    elif selected_farm_geom:
        # Check if the geometry is a Point
        is_point_geom = False
        try:
            if selected_farm_geom.type().getInfo() == 'Point':
                is_point_geom = True
        except Exception: # Fallback for non-EE geometry or error in getInfo
            if isinstance(selected_farm_geom, ee.geometry.Point):
                 is_point_geom = True


        if is_point_geom:
            timeseries_end_date = today.strftime('%Y-%m-%d')
            timeseries_start_date = (today - datetime.timedelta(days=365*2)).strftime('%Y-%m-%d') # 2 years of data
            ts_df, ts_error = get_index_time_series(
                selected_farm_geom, selected_index,
                start_date=timeseries_start_date, end_date=timeseries_end_date
            )
            if ts_error:
                st.warning(f"خطا در دریافت داده‌های سری زمانی: {ts_error}")
            elif not ts_df.empty:
                fig = px.line(ts_df, y=selected_index, title=f"روند زمانی {selected_index} برای {selected_farm_name}")
                fig.update_layout(xaxis_title="تاریخ", yaxis_title=selected_index, font=dict(family="Vazirmatn"))
                st.plotly_chart(fig, use_container_width=True)
                st.caption(f"نمودار تغییرات شاخص {selected_index} برای مزرعه {selected_farm_name} در 2 سال گذشته.")
            else:
                st.info(f"داده‌ای برای نمایش نمودار سری زمانی {selected_index} در بازه مشخص شده یافت نشد.")
        else:
            st.warning("نمودار سری زمانی فقط برای مزارع منفرد (نقطه‌ای) قابل نمایش است.")
    else:
        st.warning("هندسه مزرعه برای نمودار سری زمانی در دسترس نیست.")


with tab3:
    st.header("💡 تحلیل هوشمند با Gemini")
    st.markdown("""
    **توجه:** پاسخ‌های ارائه شده توسط هوش مصنوعی Gemini بر اساس داده‌های موجود و الگوهای کلی تولید می‌شوند و نباید جایگزین نظر کارشناسان کشاورزی شوند. همیشه برای تصمیم‌گیری‌های مهم با متخصصین مشورت کنید.
    """)

    if not gemini_model:
        st.warning("⚠️ برای استفاده از قابلیت‌های هوشمند، لطفاً کلید API جمینای خود را در نوار کناری وارد کنید.")
    else:
        st.subheader("💬 پاسخ هوشمند به سوالات در مورد داده‌های مزارع")
        user_farm_q = st.text_input("سوال خود را در مورد مزرعه انتخاب شده یا وضعیت کلی مزارع بپرسید:", key="gemini_farm_q")
        if st.button("✉️ ارسال سوال به Gemini", key="btn_gemini_farm_q"):
            if not user_farm_q:
                st.info("لطفاً سوال خود را وارد کنید.")
            else:
                prompt = ""
                context_data = ""
                if selected_farm_name != "همه مزارع" and selected_farm_details is not None and not ranking_df_sorted.empty:
                    farm_data_for_prompt = ranking_df_sorted[ranking_df_sorted['مزرعه'] == selected_farm_name]
                    if not farm_data_for_prompt.empty:
                        current_val_str = farm_data_for_prompt[f'{selected_index} (هفته جاری)'].iloc[0]
                        prev_val_str = farm_data_for_prompt[f'{selected_index} (هفته قبل)'].iloc[0]
                        change_str = farm_data_for_prompt['تغییر'].iloc[0]
                        status_str = farm_data_for_prompt['وضعیت'].iloc[0]
                        context_data = f"داده‌های مزرعه '{selected_farm_name}' برای شاخص {selected_index} (هفته منتهی به {end_date_current_str}):\n" \
                                       f"- مقدار هفته جاری: {current_val_str}\n" \
                                       f"- مقدار هفته قبل: {prev_val_str}\n" \
                                       f"- تغییر نسبت به هفته قبل: {change_str}\n" \
                                       f"- وضعیت کلی: {status_str}\n"
                        prompt = f"شما یک دستیار هوشمند برای تحلیل داده‌های کشاورزی نیشکر هستید. کاربر در مورد مزرعه '{selected_farm_name}' سوالی پرسیده است: '{user_farm_q}'.\n{context_data}\nلطفاً بر اساس این داده‌ها و سوال کاربر، یک پاسخ جامع و مفید به زبان فارسی ارائه دهید."
                    else:
                        prompt = f"شما یک دستیار هوشمند برای تحلیل داده‌های کشاورزی نیشکر هستید. کاربر در مورد مزرعه '{selected_farm_name}' سوالی پرسیده است: '{user_farm_q}'. داده‌های رتبه‌بندی برای این مزرعه در دسترس نیست. لطفاً به صورت کلی و بر اساس سوال کاربر پاسخ دهید. پاسخ به زبان فارسی."

                else: # "همه مزارع" or no specific farm data
                    context_data = f"وضعیت کلی مزارع برای روز '{selected_day}' و شاخص '{selected_index}' در حال بررسی است. تعداد {len(filtered_farms_df)} مزرعه در این روز فیلتر شده‌اند."
                    if not ranking_df_sorted.empty:
                        context_data += f"\nخلاصه وضعیت مزارع بر اساس شاخص {selected_index}:\n"
                        status_counts = ranking_df_sorted['وضعیت'].value_counts()
                        context_data += f"- تعداد مزارع با بهبود/رشد: {status_counts.get('رشد مثبت', 0) + status_counts.get('بهبود', 0)}\n"
                        context_data += f"- تعداد مزارع با وضعیت ثابت: {status_counts.get('ثابت', 0)}\n"
                        context_data += f"- تعداد مزارع با تنش/کاهش: {status_counts.get('تنش/کاهش', 0) + status_counts.get('تنش/بدتر شدن', 0)}\n"
                        context_data += f"- تعداد مزارع بدون داده: {status_counts.get('بدون داده', 0)}\n"

                    prompt = f"شما یک دستیار هوشمند برای تحلیل داده‌های کشاورزی نیشکر هستید. کاربر سوالی در مورد وضعیت کلی مزارع پرسیده است: '{user_farm_q}'.\n{context_data}\nلطفاً بر اساس این اطلاعات و سوال کاربر، یک پاسخ جامع و مفید به زبان فارسی ارائه دهید."

                with st.spinner("در حال پردازش پاسخ با Gemini..."):
                    response = ask_gemini(prompt)
                    st.markdown(response)
        st.markdown("---")

        st.subheader("📄 تولید گزارش خودکار هفتگی برای مزرعه")
        if selected_farm_name == "همه مزارع":
            st.info("لطفاً یک مزرعه خاص را برای تولید گزارش انتخاب کنید.")
        elif selected_farm_details is None:
            st.info(f"داده‌های جزئی برای مزرعه {selected_farm_name} یافت نشد.")
        elif ranking_df_sorted.empty:
            st.info(f"داده‌های رتبه‌بندی برای مزرعه {selected_farm_name} جهت تولید گزارش موجود نیست.")
        else:
            if st.button(f"📝 تولید گزارش برای مزرعه '{selected_farm_name}'", key="btn_gemini_report"):
                farm_data_for_report = ranking_df_sorted[ranking_df_sorted['مزرعه'] == selected_farm_name]
                if not farm_data_for_report.empty:
                    current_val_str = farm_data_for_report[f'{selected_index} (هفته جاری)'].iloc[0]
                    prev_val_str = farm_data_for_report[f'{selected_index} (هفته قبل)'].iloc[0]
                    change_str = farm_data_for_report['تغییر'].iloc[0]
                    status_str = farm_data_for_report['وضعیت'].iloc[0]
                    area_str = f"{selected_farm_details.get('مساحت', 'N/A'):,.2f}" if pd.notna(selected_farm_details.get('مساحت')) else "N/A"
                    variety_str = selected_farm_details.get('واریته', 'N/A')

                    prompt = f"شما یک دستیار هوشمند برای تهیه گزارش‌های کشاورزی هستید. لطفاً یک گزارش توصیفی و ساختاریافته به زبان فارسی در مورد وضعیت مزرعه '{selected_farm_name}' برای هفته منتهی به {end_date_current_str} تهیه کنید.\n" \
                             f"اطلاعات مزرعه:\n" \
                             f"- مساحت: {area_str} هکتار\n" \
                             f"- واریته: {variety_str}\n" \
                             f"- شاخص مورد بررسی: {selected_index} ({index_options[selected_index]})\n" \
                             f"- مقدار شاخص در هفته جاری: {current_val_str}\n" \
                             f"- مقدار شاخص در هفته قبل: {prev_val_str}\n" \
                             f"- تغییر نسبت به هفته قبل: {change_str}\n" \
                             f"- وضعیت کلی بر اساس تغییرات: {status_str}\n\n" \
                             f"در گزارش به موارد فوق اشاره کنید، تحلیل مختصری از وضعیت ارائه دهید و در صورت امکان، پیشنهادهای کلی (نه تخصصی) برای بهبود یا حفظ وضعیت مطلوب بیان کنید. گزارش باید رسمی و قابل فهم برای مدیران کشاورزی باشد."

                    with st.spinner("در حال تولید گزارش با Gemini..."):
                        response = ask_gemini(prompt, temperature=0.6, top_p=0.9)
                        st.markdown(f"### گزارش هفتگی مزرعه {selected_farm_name} (شاخص {selected_index})")
                        st.markdown(f"**تاریخ گزارش:** {datetime.date.today().strftime('%Y-%m-%d')}")
                        st.markdown(f"**بازه زمانی مورد بررسی:** {start_date_current_str} الی {end_date_current_str}")
                        st.markdown(response)
                else:
                    st.error(f"داده‌های کافی برای تولید گزارش برای مزرعه {selected_farm_name} یافت نشد.")
        st.markdown("---")

        st.subheader(f"📉 تحلیل تغییرات شاخص {selected_index} (سری زمانی)")
        if selected_farm_name == "همه مزارع":
            st.info("لطفاً یک مزرعه خاص را برای تحلیل سری زمانی انتخاب کنید.")
        elif selected_farm_geom:
            is_point_geom_gemini = False
            try:
                if selected_farm_geom.type().getInfo() == 'Point': is_point_geom_gemini = True
            except Exception:
                if isinstance(selected_farm_geom, ee.geometry.Point): is_point_geom_gemini = True

            if is_point_geom_gemini:
                if st.button(f"🔍 تحلیل روند زمانی {selected_index} برای '{selected_farm_name}'", key="btn_gemini_timeseries"):
                    timeseries_end_date_gemini = today.strftime('%Y-%m-%d')
                    timeseries_start_date_gemini = (today - datetime.timedelta(days=180)).strftime('%Y-%m-%d') # Last 6 months
                    ts_df_gemini, ts_error_gemini = get_index_time_series(
                        selected_farm_geom, selected_index,
                        start_date=timeseries_start_date_gemini, end_date=timeseries_end_date_gemini
                    )
                    if ts_error_gemini:
                        st.error(f"خطا در دریافت داده‌های سری زمانی برای Gemini: {ts_error_gemini}")
                    elif not ts_df_gemini.empty:
                        # Prepare a summary of time series for the prompt
                        ts_summary = f"داده‌های سری زمانی شاخص {selected_index} برای مزرعه '{selected_farm_name}' در 6 ماه گذشته (از {timeseries_start_date_gemini} تا {timeseries_end_date_gemini}):\n"
                        ts_summary += ts_df_gemini.iloc[::len(ts_df_gemini)//5 if len(ts_df_gemini)>5 else 1].to_string(header=True, index=True) # Sample ~5 points
                        ts_summary += f"\nمقدار اولیه حدود {ts_df_gemini[selected_index].iloc[0]:.3f} و مقدار نهایی حدود {ts_df_gemini[selected_index].iloc[-1]:.3f} بوده است."
                        
                        prompt = f"شما یک تحلیلگر داده‌های کشاورزی هستید. بر اساس داده‌های سری زمانی زیر برای شاخص {selected_index} مزرعه '{selected_farm_name}' طی 6 ماه گذشته:\n{ts_summary}\n" \
                                 f"۱. روند کلی تغییرات شاخص (افزایشی، کاهشی، نوسانی، ثابت) را توصیف کنید.\n" \
                                 f"۲. نقاط عطف یا تغییرات قابل توجه در روند را شناسایی کنید (اگر وجود دارد).\n" \
                                 f"۳. دلایل احتمالی کلی (مانند تغییرات فصلی، مراحل رشد گیاه، تنش‌های محیطی عمومی) برای این روندها چه می‌تواند باشد؟\n" \
                                 f"پاسخ به زبان فارسی، ساختاریافته و تحلیلی باشد."
                        with st.spinner(f"در حال تحلیل روند زمانی {selected_index} با Gemini..."):
                            response = ask_gemini(prompt, temperature=0.5)
                            st.markdown(response)
                    else:
                        st.info(f"داده‌ای برای تحلیل سری زمانی {selected_index} برای مزرعه {selected_farm_name} یافت نشد.")
            else:
                st.info("تحلیل سری زمانی فقط برای مزارع منفرد (نقطه‌ای) امکان‌پذیر است.")
        st.markdown("---")

        st.subheader("🌱 پیشنهاد اقدامات کشاورزی")
        if selected_farm_name == "همه مزارع":
            st.info("لطفاً یک مزرعه خاص را برای دریافت پیشنهادات انتخاب کنید.")
        elif selected_farm_details is None or ranking_df_sorted.empty :
             st.info(f"داده‌های کافی برای ارائه پیشنهاد برای مزرعه {selected_farm_name} موجود نیست.")
        else:
            if st.button(f"💡 دریافت پیشنهادات برای مزرعه '{selected_farm_name}'", key="btn_gemini_actions"):
                farm_data_for_actions = ranking_df_sorted[ranking_df_sorted['مزرعه'] == selected_farm_name]
                if not farm_data_for_actions.empty:
                    current_val_str = farm_data_for_actions[f'{selected_index} (هفته جاری)'].iloc[0]
                    status_str = farm_data_for_actions['وضعیت'].iloc[0]

                    prompt = f"شما یک مشاور کشاورزی هوشمند هستید. برای مزرعه '{selected_farm_name}'، شاخص {selected_index} ({index_options[selected_index]}) در هفته جاری مقدار {current_val_str} را نشان می‌دهد و وضعیت کلی آن '{status_str}' ارزیابی شده است.\n" \
                             f"بر اساس این اطلاعات:\n" \
                             f"۱. تفسیر مختصری از مقدار فعلی شاخص {selected_index} ارائه دهید (مثلاً اگر NDVI پایین است، یعنی چه؟ اگر MSI بالاست یعنی چه؟).\n" \
                             f"۲. با توجه به مقدار شاخص و وضعیت، چه نوع بررسی‌ها یا اقدامات عمومی کشاورزی (مانند بررسی آبیاری، نیاز به عناصر غذایی، پایش آفات و بیماری‌ها، مدیریت بقایا) ممکن است لازم باشد؟ لطفاً پیشنهادات کلی و غیر تخصصی ارائه دهید.\n" \
                             f"پاسخ به زبان فارسی و به صورت عملیاتی باشد."

                    with st.spinner("در حال دریافت پیشنهادات کشاورزی با Gemini..."):
                        response = ask_gemini(prompt, temperature=0.8, top_k=30)
                        st.markdown(response)
                else:
                    st.error(f"داده‌های رتبه‌بندی برای مزرعه {selected_farm_name} جهت ارائه پیشنهاد یافت نشد.")
        st.markdown("---")

        st.subheader("🗣️ پاسخ به سوالات عمومی کاربران")
        user_general_q = st.text_input("سوال عمومی خود را در مورد مفاهیم کشاورزی، شاخص‌های سنجش از دور یا این سامانه بپرسید:", key="gemini_general_q")
        if st.button("❓ پرسیدن سوال از Gemini", key="btn_gemini_general_q"):
            if not user_general_q:
                st.info("لطفاً سوال خود را وارد کنید.")
            else:
                prompt = f"شما یک دانشنامه هوشمند در زمینه کشاورزی و سنجش از دور هستید. لطفاً به سوال زیر که توسط یک کاربر سامانه پایش نیشکر پرسیده شده است، به زبان فارسی پاسخ دهید. سعی کنید پاسخ شما ساده، قابل فهم و دقیق باشد.\n\nسوال کاربر: '{user_general_q}'"
                if "مزرعه من قرمز شده" in user_general_q or "مزرعه قرمز" in user_general_q: # Heuristic
                     if selected_farm_name != "همه مزارع" and not ranking_df_sorted.empty:
                        farm_data_color = ranking_df_sorted[ranking_df_sorted['مزرعه'] == selected_farm_name]
                        if not farm_data_color.empty and selected_index in ['NDVI', 'EVI', 'LAI', 'CVI']: # Indices where red is bad
                            current_val_color = farm_data_color[f'{selected_index} (هفته جاری)'].iloc[0]
                            prompt = f"شما یک دانشنامه هوشمند در زمینه کشاورزی و سنجش از دور هستید. کاربر پرسیده: '{user_general_q}'. در این سامانه، رنگ قرمز روی نقشه برای شاخص‌هایی مانند NDVI معمولاً نشان‌دهنده مقدار پایین و وضعیت نامطلوب پوشش گیاهی است. برای مزرعه '{selected_farm_name}'، مقدار فعلی شاخص {selected_index} برابر {current_val_color} است. لطفاً توضیح دهید که چه عواملی می‌توانند باعث پایین بودن این شاخص و 'قرمز' دیده شدن مزرعه در نقشه شوند و چه بررسی‌هایی ممکن است لازم باشد. پاسخ به زبان فارسی."


                with st.spinner("در حال جستجو برای پاسخ با Gemini..."):
                    response = ask_gemini(prompt, temperature=0.3)
                    st.markdown(response)

st.sidebar.markdown("---")
st.sidebar.markdown("ساخته شده با 💻 توسط [اسماعیل کیانی] با استفاده از Streamlit, Google Earth Engine, geemap و Gemini API")
st.sidebar.markdown("🌾 شرکت کشت و صنعت دهخدا")