File size: 128,946 Bytes
4dd9e3d
297caf8
cde4684
bcfae1d
2aa2018
 
 
297caf8
bcfae1d
d7a9dae
2aa2018
 
 
 
297caf8
 
 
d7a9dae
297caf8
d7a9dae
9e1838c
297caf8
4dd9e3d
 
 
 
18a37d3
 
ac4c899
297caf8
 
 
9e1838c
4dd9e3d
 
 
297caf8
 
d7a9dae
297caf8
 
 
 
 
 
 
 
 
9e1838c
9b151b7
 
 
 
 
 
 
 
 
 
 
 
 
2aa2018
297caf8
 
 
 
 
 
d7a9dae
297caf8
 
 
 
 
d7a9dae
 
297caf8
 
 
d7a9dae
 
297caf8
 
d7a9dae
297caf8
 
 
 
d7a9dae
297caf8
 
2aa2018
 
0a377ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4dd9e3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2aa2018
297caf8
 
d7a9dae
297caf8
 
 
 
a888e5d
d7a9dae
297caf8
2e68678
d7a9dae
2e68678
 
d7a9dae
2e68678
297caf8
 
 
d7a9dae
 
 
 
 
 
 
 
 
297caf8
 
2e68678
297caf8
 
 
 
 
 
2e68678
d7a9dae
 
 
 
 
 
 
 
 
 
 
2e68678
297caf8
 
2e68678
d7a9dae
 
 
 
 
 
 
 
 
 
 
 
 
2e68678
297caf8
 
 
d7a9dae
2e68678
9e1838c
d7a9dae
297caf8
 
 
 
d7a9dae
 
 
 
 
297caf8
 
4dd9e3d
 
 
 
297caf8
 
2aa2018
 
297caf8
d7a9dae
 
 
 
 
 
 
 
297caf8
d7a9dae
 
2e68678
9e1838c
297caf8
2e68678
9e1838c
2aa2018
2e68678
d7a9dae
 
2e68678
 
 
d7a9dae
2e68678
 
 
 
 
 
d7a9dae
2aa2018
9b151b7
 
2aa2018
2dd9b40
 
2aa2018
9b151b7
2dd9b40
2aa2018
9b151b7
 
2dd9b40
 
2aa2018
 
2dd9b40
2aa2018
2dd9b40
 
 
 
9b151b7
 
2dd9b40
9b151b7
2aa2018
9b151b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2aa2018
37ff2cb
297caf8
 
d7a9dae
2e68678
 
297caf8
2e68678
 
 
297caf8
d7a9dae
297caf8
 
d7a9dae
 
 
 
297caf8
 
2e68678
297caf8
 
 
d7a9dae
2e68678
297caf8
 
 
 
d7a9dae
297caf8
 
 
 
 
2e68678
297caf8
37ff2cb
297caf8
 
 
2e68678
d7a9dae
 
 
 
 
 
 
 
 
 
 
 
4dd9e3d
d7a9dae
4dd9e3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d7a9dae
297caf8
 
 
2e68678
297caf8
37ff2cb
297caf8
 
 
2e68678
297caf8
d7a9dae
 
297caf8
 
d7a9dae
 
297caf8
 
 
 
 
 
 
 
2e68678
2aa2018
2e68678
d7a9dae
297caf8
 
2e68678
297caf8
d7a9dae
 
297caf8
 
 
2e68678
297caf8
37ff2cb
297caf8
 
 
2e68678
297caf8
d7a9dae
 
297caf8
 
 
 
d7a9dae
297caf8
d7a9dae
297caf8
d7a9dae
 
 
 
 
297caf8
d7a9dae
297caf8
d7a9dae
297caf8
 
d7a9dae
 
297caf8
d7a9dae
 
297caf8
2e68678
297caf8
 
 
 
2e68678
d7a9dae
 
 
 
 
2e68678
297caf8
 
 
 
2e68678
d7a9dae
 
 
 
 
 
2e68678
297caf8
 
 
 
2e68678
d7a9dae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297caf8
2e68678
297caf8
 
 
 
2e68678
d7a9dae
 
 
 
 
2e68678
297caf8
 
 
 
2e68678
 
d7a9dae
 
 
 
 
 
 
 
 
297caf8
d7a9dae
 
 
 
 
 
 
297caf8
 
2e68678
297caf8
 
 
 
2e68678
d7a9dae
 
 
 
 
 
2e68678
297caf8
5746aa7
 
297caf8
2e68678
297caf8
d7a9dae
5746aa7
 
 
 
 
 
 
 
 
 
 
 
 
 
d7a9dae
297caf8
2e68678
5746aa7
297caf8
9b151b7
297caf8
 
2e68678
9b151b7
5746aa7
9b151b7
297caf8
2e68678
9b151b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5746aa7
 
9b151b7
 
 
 
 
 
 
5746aa7
 
2e68678
5746aa7
 
 
d1a4128
2aa2018
4dd9e3d
d7a9dae
 
4dd9e3d
 
 
297caf8
 
d7a9dae
4dd9e3d
 
 
 
 
 
 
 
 
 
 
297caf8
4dd9e3d
 
 
 
 
 
 
 
d7a9dae
 
297caf8
 
 
 
2e68678
d7a9dae
 
 
 
2e68678
297caf8
 
 
 
2e68678
d7a9dae
 
 
 
2e68678
297caf8
73c2b9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4dd9e3d
2aa2018
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4dd9e3d
 
2aa2018
 
 
 
 
10fc744
4dd9e3d
 
 
 
 
 
 
 
 
 
 
 
2aa2018
 
 
 
 
 
 
 
 
10fc744
2aa2018
 
 
 
 
 
 
 
10fc744
2aa2018
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297caf8
 
2e68678
297caf8
2e68678
 
d7a9dae
297caf8
d7a9dae
4dd9e3d
 
 
297caf8
4dd9e3d
297caf8
 
 
 
 
 
 
2e68678
297caf8
 
 
 
2e68678
d7a9dae
2e68678
d7a9dae
 
 
2e68678
297caf8
 
 
 
2e68678
297caf8
2e68678
d7a9dae
 
 
 
 
297caf8
 
 
 
2e68678
297caf8
2aa2018
 
 
 
 
 
 
 
 
 
 
 
 
 
10fc744
2aa2018
 
 
 
 
10fc744
2aa2018
 
 
 
 
 
 
 
 
 
297caf8
 
fa37fed
10fc744
 
 
d7a9dae
fa37fed
 
2aa2018
10fc744
2aa2018
fa37fed
2aa2018
d7a9dae
fa37fed
 
 
 
10fc744
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2e68678
fa37fed
 
 
 
 
2e68678
fa37fed
 
 
2aa2018
2e68678
fa37fed
 
 
 
2e68678
fa37fed
2e68678
 
 
 
 
fa37fed
 
 
 
 
 
 
10fc744
 
fa37fed
 
 
 
 
 
 
2aa2018
10fc744
 
 
 
 
fa37fed
10fc744
fa37fed
2aa2018
fa37fed
 
 
 
2aa2018
fa37fed
10fc744
 
fa37fed
 
2aa2018
fa37fed
 
 
 
 
 
 
 
2e68678
d7a9dae
fa37fed
2aa2018
10fc744
2aa2018
fa37fed
 
 
 
 
2aa2018
2e68678
 
 
10fc744
 
 
 
2e68678
2aa2018
2e68678
fa37fed
10fc744
2e68678
2aa2018
2e68678
10fc744
fa37fed
2aa2018
 
fa37fed
10fc744
 
2e68678
297caf8
 
14b1751
10fc744
 
 
d7a9dae
10fc744
d7a9dae
2aa2018
2e68678
14b1751
10fc744
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2e68678
 
 
 
 
 
 
 
 
14b1751
 
 
 
 
 
 
 
 
10fc744
14b1751
10fc744
14b1751
 
 
 
10fc744
14b1751
2aa2018
d7a9dae
2aa2018
14b1751
 
10fc744
14b1751
10fc744
14b1751
2aa2018
14b1751
 
2e68678
 
14b1751
2e68678
10fc744
 
 
 
d7a9dae
14b1751
10fc744
14b1751
 
 
 
 
2aa2018
14b1751
 
 
 
 
 
2aa2018
14b1751
 
10fc744
14b1751
 
 
10fc744
14b1751
 
 
 
 
 
10fc744
 
2aa2018
14b1751
 
 
 
2e68678
 
 
10fc744
2aa2018
10fc744
2aa2018
d7a9dae
14b1751
 
10fc744
14b1751
 
 
10fc744
14b1751
 
 
 
 
 
10fc744
 
14b1751
 
10fc744
2aa2018
2e68678
10fc744
2e68678
 
2aa2018
2e68678
2aa2018
2e68678
2aa2018
2e68678
 
 
 
 
 
 
 
 
 
 
2aa2018
2e68678
2aa2018
2e68678
 
 
 
 
2aa2018
 
2e68678
 
2aa2018
2e68678
 
 
2aa2018
2e68678
 
 
2aa2018
2e68678
 
2aa2018
2e68678
 
 
 
 
2aa2018
2e68678
2aa2018
2e68678
 
 
 
 
 
 
2aa2018
2e68678
 
2aa2018
2e68678
 
 
 
 
 
2aa2018
 
2e68678
 
 
 
 
 
2aa2018
2e68678
 
 
 
2aa2018
2e68678
 
 
 
 
 
 
 
 
2aa2018
2e68678
2aa2018
2e68678
 
 
 
2aa2018
2e68678
2aa2018
 
2e68678
 
 
 
 
2aa2018
2e68678
2aa2018
2e68678
 
2aa2018
2e68678
297caf8
2aa2018
 
 
 
 
 
 
 
 
 
 
 
 
 
10fc744
2aa2018
 
 
 
10fc744
2aa2018
 
 
 
 
 
 
10fc744
2aa2018
 
 
 
 
 
 
 
 
 
 
 
 
10fc744
2aa2018
 
 
 
4dd9e3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e9aee0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2aa2018
5e9aee0
 
 
 
 
 
 
 
 
 
2aa2018
2e68678
5e9aee0
 
 
 
 
 
 
 
 
 
 
 
 
2e68678
5e9aee0
 
 
 
 
2e68678
5e9aee0
 
 
 
2aa2018
5e9aee0
 
 
2e68678
5e9aee0
 
 
 
 
2aa2018
5e9aee0
 
2e68678
5e9aee0
 
 
 
2aa2018
5e9aee0
 
 
2e68678
5e9aee0
 
 
2e68678
5e9aee0
 
 
 
2e68678
5e9aee0
2e68678
5e9aee0
2e68678
5e9aee0
 
 
 
 
 
 
 
 
 
 
2e68678
 
 
2aa2018
2e68678
2aa2018
2e68678
 
 
 
5e9aee0
 
 
 
 
 
 
 
 
 
 
 
2e68678
5e9aee0
 
 
 
2e68678
5e9aee0
2aa2018
5e9aee0
 
2aa2018
5e9aee0
2aa2018
5e9aee0
 
 
 
 
 
2e68678
5e9aee0
 
2e68678
5e9aee0
2aa2018
5e9aee0
 
 
2e68678
2aa2018
 
5e9aee0
2e68678
5e9aee0
 
2e68678
5e9aee0
 
 
 
 
 
2e68678
2aa2018
5e9aee0
2e68678
 
5e9aee0
 
2e68678
2aa2018
5e9aee0
 
 
 
 
2e68678
5e9aee0
 
 
 
 
 
 
 
 
2e68678
5e9aee0
 
 
2e68678
5e9aee0
2aa2018
5e9aee0
 
 
2e68678
 
5e9aee0
2e68678
5e9aee0
2e68678
5e9aee0
 
 
2e68678
5e9aee0
 
 
 
2e68678
2aa2018
5e9aee0
2aa2018
5e9aee0
 
2e68678
5e9aee0
 
2e68678
 
2aa2018
2e68678
 
 
 
5e9aee0
 
2aa2018
5e9aee0
2e68678
5e9aee0
2e68678
5e9aee0
 
 
 
 
 
 
 
 
 
 
 
2e68678
5e9aee0
 
 
 
 
 
 
 
2e68678
5e9aee0
2aa2018
5e9aee0
 
2aa2018
5e9aee0
2e68678
5e9aee0
 
 
 
 
 
 
 
 
 
 
2e68678
5e9aee0
 
2e68678
5e9aee0
2e68678
5e9aee0
 
2aa2018
5e9aee0
2e68678
5e9aee0
 
2e68678
5e9aee0
2e68678
5e9aee0
 
 
2e68678
5e9aee0
 
 
 
 
 
2aa2018
5e9aee0
 
2e68678
 
 
 
5e9aee0
 
2e68678
5e9aee0
2e68678
5e9aee0
2e68678
5e9aee0
 
2e68678
2aa2018
 
d1a4128
 
 
 
 
2aa2018
d1a4128
 
 
 
2aa2018
 
d1a4128
 
2aa2018
d1a4128
 
 
 
 
 
 
2aa2018
d1a4128
 
 
 
2aa2018
 
d1a4128
 
2aa2018
d1a4128
482037a
2aa2018
 
c75cb71
 
 
 
 
 
2aa2018
c75cb71
 
 
 
 
 
 
 
 
 
2aa2018
c75cb71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2aa2018
c75cb71
 
 
 
 
 
 
 
 
 
 
 
 
 
2aa2018
c75cb71
 
 
 
 
 
2aa2018
c75cb71
2aa2018
c75cb71
 
 
 
 
 
 
 
 
 
 
2aa2018
c75cb71
 
 
 
 
 
 
2aa2018
c75cb71
 
 
 
 
 
 
 
 
 
 
2aa2018
c75cb71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2aa2018
c75cb71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2aa2018
c75cb71
 
 
2aa2018
c75cb71
 
 
 
 
 
 
2aa2018
297caf8
 
 
2e68678
d7a9dae
2e68678
d7a9dae
 
 
2e68678
297caf8
 
 
 
2e68678
d7a9dae
2e68678
d7a9dae
 
 
 
2e68678
d7a9dae
 
2e68678
d7a9dae
 
2e68678
d7a9dae
 
2e68678
 
2aa2018
 
2e68678
 
 
297caf8
 
d7a9dae
 
 
 
 
 
 
 
 
 
 
2e68678
297caf8
 
 
d7a9dae
 
297caf8
d7a9dae
 
 
 
2e68678
297caf8
 
 
 
2e68678
d7a9dae
 
 
9b151b7
d7a9dae
9b151b7
 
 
 
 
 
 
 
 
 
 
 
 
 
d7a9dae
 
9b151b7
d7a9dae
 
 
9b151b7
 
d7a9dae
9b151b7
d7a9dae
9b151b7
 
 
 
 
d7a9dae
 
9b151b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297caf8
 
 
d7a9dae
 
297caf8
d7a9dae
2aa2018
 
d7a9dae
297caf8
 
 
2e68678
297caf8
 
 
d7a9dae
 
297caf8
d7a9dae
 
 
 
297caf8
 
2e68678
297caf8
2aa2018
 
 
10fc744
2aa2018
 
10fc744
2aa2018
 
10fc744
2aa2018
 
 
 
 
10fc744
2aa2018
 
 
10fc744
2aa2018
 
10fc744
2aa2018
 
 
10fc744
2aa2018
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10fc744
2aa2018
 
 
 
 
 
 
 
 
 
 
 
 
 
f36a56f
2aa2018
 
 
 
 
 
297caf8
 
2aa2018
 
297caf8
d7a9dae
 
 
10fc744
2aa2018
10fc744
2aa2018
 
10fc744
2aa2018
2e68678
 
 
297caf8
2aa2018
2e68678
d7a9dae
297caf8
 
e0f7143
d7a9dae
e0f7143
d7a9dae
2868e10
 
05c0163
d7a9dae
e0f7143
2868e10
e871aa6
 
e0f7143
2868e10
 
 
 
e0f7143
2868e10
e0f7143
 
 
 
 
 
 
 
 
 
 
 
f36a56f
e0f7143
 
 
 
 
 
 
 
 
e871aa6
e0f7143
 
 
 
2868e10
 
e0f7143
 
2868e10
 
 
e0f7143
2868e10
e0f7143
 
2868e10
e0f7143
2868e10
e0f7143
2868e10
2bc1d5b
 
 
e0f7143
2bc1d5b
 
 
 
 
 
 
 
 
05c0163
2bc1d5b
e0f7143
2bc1d5b
e0f7143
 
 
 
 
 
 
 
 
e871aa6
 
 
 
 
 
 
 
 
e0f7143
 
d7a9dae
2868e10
e0f7143
 
 
 
 
 
 
 
 
297caf8
 
 
d7a9dae
 
297caf8
d7a9dae
 
 
 
297caf8
 
d7a9dae
2e68678
297caf8
0a377ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297caf8
4dd9e3d
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
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434

from flask import Flask, request, jsonify
import os
import json

import time # Not actively used
import base64 # Not actively used
import uuid
from flask_cors import CORS
from google import genai

from PIL import Image # Not actively used
import io # Not actively used
from typing import List, Dict, Any # Not actively used
import logging
import traceback
from datetime import datetime, timezone
import re

from firebase_admin import credentials, db, storage, auth, exceptions as firebase_exceptions
import firebase_admin

# --- NEW: Geolocation Libraries ---
import geohash as pgh
from haversine import haversine, Unit

app = Flask(__name__)
CORS(app)

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# --- NEW: Geolocation Configuration ---
GEOHASH_PRECISION = 7 # A good balance. ~153m x 153m area.

# Configure GenAI (Gemini)
GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
gemini_client = None
if not GOOGLE_API_KEY:
    logger.warning("GOOGLE_API_KEY environment variable is not set. AI features will be disabled.")
else:
    try:
        gemini_client = genai.Client(api_key=GOOGLE_API_KEY)
        logger.info("Gemini AI Client initialized successfully using genai.Client().")
    except Exception as e:
        logger.error(f"Failed to initialize Gemini AI Client with genai.Client(): {e}")
        gemini_client = None

import resend
# NEW: Initialize the Resend client using environment variables
# This should be placed near your other initializations at the top of the file.
if 'RESEND_API_KEY' in os.environ:
    resend.api_key = os.environ["RESEND_API_KEY"]
    SENDER_EMAIL = os.environ.get("SENDER_EMAIL")
    if not SENDER_EMAIL:
        logger.warning("RESEND_API_KEY is set, but SENDER_EMAIL is not. Emails will not be sent.")
        resend.api_key = None # Disable client if sender is not configured
else:
    logger.info("RESEND_API_KEY environment variable not found. Email notifications will be disabled.")
    resend.api_key = None

#--- Firebase Initialization ---
FIREBASE_CREDENTIALS_JSON_STRING = os.getenv("FIREBASE")
FIREBASE_DB_URL = os.getenv("Firebase_DB")
FIREBASE_STORAGE_BUCKET = os.getenv("Firebase_Storage")

FIREBASE_INITIALIZED = False
bucket = None
db_app = None

try:
    if FIREBASE_CREDENTIALS_JSON_STRING and FIREBASE_DB_URL and FIREBASE_STORAGE_BUCKET:
        credentials_json = json.loads(FIREBASE_CREDENTIALS_JSON_STRING)
        cred = credentials.Certificate(credentials_json)
        if not firebase_admin._apps:
            db_app = firebase_admin.initialize_app(cred, {
                'databaseURL': FIREBASE_DB_URL,
                'storageBucket': FIREBASE_STORAGE_BUCKET
            })
        else:
            db_app = firebase_admin.get_app()

        FIREBASE_INITIALIZED = True
        bucket = storage.bucket(app=db_app)
        logger.info("Firebase Admin SDK initialized successfully.")
    else:
        logger.error("Firebase environment variables (FIREBASE, Firebase_DB, Firebase_Storage) not fully set. Firebase Admin SDK not initialized.")
except Exception as e:
    logger.error(f"CRITICAL: Error initializing Firebase: {e}")
    traceback.print_exc()

#--- END Firebase Initialization ---


# Paynow #
# --- Paynow Initialization ---
from paynow import Paynow

PAYNOW_INTEGRATION_ID = os.getenv("PAYNOW_INTEGRATION_ID")
PAYNOW_INTEGRATION_KEY = os.getenv("PAYNOW_INTEGRATION_KEY")
# IMPORTANT: This should be the publicly accessible URL of your deployed application
APP_BASE_URL = os.getenv("APP_BASE_URL", "https://tunasongaagri.co.zw") 

paynow_client = None
if PAYNOW_INTEGRATION_ID and PAYNOW_INTEGRATION_KEY:
    try:
        paynow_client = Paynow(
            PAYNOW_INTEGRATION_ID,
            PAYNOW_INTEGRATION_KEY,
            return_url=f"{APP_BASE_URL}/my-deals", # A page for the user to land on after payment
            result_url=f"{APP_BASE_URL}/api/payment/webhook/paynow" # The webhook URL for server-to-server updates
        )
        logger.info("Paynow client initialized successfully.")
    except Exception as e:
        logger.error(f"Failed to initialize Paynow client: {e}")
else:
    logger.warning("Paynow environment variables not set. Payment features will be disabled.")

#--- NEW: Geolocation Helpers ---
def _calculate_geohash(lat, lon):
    """Calculates the geohash for a given latitude and longitude."""
    return pgh.encode(lat, lon, precision=GEOHASH_PRECISION)

def _get_geohash_query_area(lat, lon):
    """Calculates the geohash for a point and its 8 neighbors."""
    center_geohash = _calculate_geohash(lat, lon)
    neighbors = pgh.neighbors(center_geohash)
    return [center_geohash] + neighbors

def _calculate_distance(point1_coords, point2_coords):
    """Calculates Haversine distance between two coordinate dictionaries."""
    point1 = (point1_coords['latitude'], point1_coords['longitude'])
    point2 = (point2_coords['latitude'], point2_coords['longitude'])
    return haversine(point1, point2, unit=Unit.KILOMETERS)

#--- Helper Functions ---
def verify_token(auth_header):
    if not FIREBASE_INITIALIZED:
        logger.error("verify_token: Firebase not initialized.")
        raise ConnectionError('Server configuration error: Firebase not ready.')
    if not auth_header or not auth_header.startswith('Bearer '):
        raise ValueError('Invalid token format')
    token = auth_header.split(' ')[1]
    try:
        decoded_token = auth.verify_id_token(token, app=db_app)
        return decoded_token['uid']
    except auth.AuthError as ae: # More specific Firebase Auth errors
        logger.error(f"Token verification failed (AuthError): {ae}")
        raise PermissionError(f"Token verification failed: {str(ae)}")
    except Exception as e: # Generic catch-all
        logger.error(f"Token verification failed (Generic Exception): {e}\n{traceback.format_exc()}")
        raise PermissionError(f"Token verification failed: {str(e)}")

def get_user_roles(uid):
    if not FIREBASE_INITIALIZED: return {}
    try:
        user_ref = db.reference(f'users/{uid}', app=db_app)
        user_data = user_ref.get()
        if user_data and isinstance(user_data.get('roles'), dict):
            return user_data.get('roles', {})
        return {}
    except Exception as e:
        logger.error(f"Error in get_user_roles for UID {uid}: {e}\n{traceback.format_exc()}")
        return {}

def verify_role(auth_header, required_role):
    uid = verify_token(auth_header) # Can raise PermissionError, ValueError, ConnectionError
    user_roles = get_user_roles(uid)
    if not user_roles.get(required_role, False):
        raise PermissionError(f'{required_role} access required')
    return uid

def verify_admin_or_facilitator(auth_header):
    uid = verify_token(auth_header) # Can raise
    if not FIREBASE_INITIALIZED: raise ConnectionError('Server configuration error: Firebase not ready.')
    try:
        user_ref = db.reference(f'users/{uid}', app=db_app)
        user_data = user_ref.get()
        if not user_data: raise PermissionError('User profile not found.')
        if not user_data.get('is_admin', False) and not user_data.get('is_facilitator', False):
            raise PermissionError('Admin or Facilitator access required')
        return uid, user_data.get('is_admin', False), user_data.get('is_facilitator', False)
    except firebase_exceptions.FirebaseError as fe:
        logger.error(f"Firebase error in verify_admin_or_facilitator for UID {uid}: {fe}\n{traceback.format_exc()}")
        raise ConnectionError(f"Database access error during admin/facilitator check: {fe}")
    # PermissionError from verify_token will be caught by the route handler

def verify_admin(auth_header):
    uid = verify_token(auth_header) # Can raise
    if not FIREBASE_INITIALIZED: raise ConnectionError('Server configuration error: Firebase not ready.')
    try:
        user_ref = db.reference(f'users/{uid}', app=db_app)
        user_data = user_ref.get()
        if not user_data:
            logger.warning(f"User {uid} (from token) not found in Realtime DB. Cannot verify admin status.")
            raise PermissionError('User profile not found in database. Admin access denied.')
        if not user_data.get('is_admin', False):
            raise PermissionError('Admin access required')
        return uid
    except firebase_exceptions.FirebaseError as fe:
        logger.error(f"Firebase error in verify_admin for UID {uid}: {fe}\n{traceback.format_exc()}")
        raise ConnectionError(f"Database access error during admin check: {fe}")
    # PermissionError from verify_token will be caught by the route handler

def ensure_user_profile_exists(uid, email=None, name=None, phone_number=None):
    if not FIREBASE_INITIALIZED:
        logger.error(f"ensure_user_profile_exists: Firebase not initialized. Cannot ensure profile for UID: {uid}")
        return None # Or raise ConnectionError
    try:
        user_ref = db.reference(f'users/{uid}', app=db_app)
        user_data = user_ref.get()
        if not user_data:
            logger.info(f"Creating missing Tunasonga profile for UID: {uid}")
            if not email:
                try:
                    user_record = auth.get_user(uid, app=db_app)
                    email = user_record.email
                except Exception as e_auth_get:
                    logger.error(f"Failed to get email for UID {uid} from Firebase Auth: {e_auth_get}")
            new_profile = {
                'email': email, 'name': name or "", 'phone_number': phone_number or "",
                'location': "", # Legacy text field
                'location_coords': None, # NEW: Geo object
                'geohash': None, # NEW: Geohash for indexing
                'roles': {'farmer': False, 'buyer': False, 'transporter': False},
                'role_applications': {}, 'document_references': {},
                'is_admin': False, 'is_facilitator': False,
                'created_at': datetime.now(timezone.utc).isoformat(), 'suspended': False,
                'account_type': 'webapp_registered' # Default for web app signups
            }
            user_ref.set(new_profile)
            verification = user_ref.get()
            if verification and verification.get('email') == email:
                logger.info(f"Successfully created Tunasonga profile for UID: {uid}")
                return verification
            else:
                logger.error(f"Profile creation verification failed for UID: {uid} after set.")
                return None
        return user_data
    except firebase_exceptions.FirebaseError as fe:
        logger.error(f"Firebase error in ensure_user_profile_exists for UID {uid}: {fe}\n{traceback.format_exc()}")
        return None # Or raise
    except Exception as e:
        logger.error(f"Error ensuring Tunasonga profile exists for UID {uid}: {e}\n{traceback.format_exc()}")
        return None # Or raise

#--- Universal Route Error Handler for Auth/Verification & Firebase ---
def handle_route_errors(e, uid_context="unknown"): # Added uid_context for better logging
    if isinstance(e, PermissionError):
        return jsonify({'error': str(e), 'type': 'PermissionError'}), 403
    elif isinstance(e, ValueError): # e.g. invalid token format, or bad input to int()/float()
        return jsonify({'error': str(e), 'type': 'ValueError'}), 400
    elif isinstance(e, ConnectionError): # Firebase not ready or DB access issue from helpers
        return jsonify({'error': str(e), 'type': 'ConnectionError'}), 503
    elif isinstance(e, firebase_exceptions.FirebaseError): # Catch specific Firebase SDK errors
        logger.error(f"Firebase SDK Error in route (UID context: {uid_context}): {e}\n{traceback.format_exc()}")
        return jsonify({'error': f'A Firebase error occurred: {str(e)}', 'type': 'FirebaseSDKError'}), 500
    else: # Generic catch-all for other unexpected errors
        logger.error(f"Unexpected Error in route (UID context: {uid_context}): {e}\n{traceback.format_exc()}")
        return jsonify({'error': f'An unexpected error occurred: {str(e)}', 'type': 'GenericError'}), 500

#--- system notifications ---

def _send_system_notification(user_id, message_content, notif_type, link=None, send_email=False, email_subject=None, email_body=None):
    if not FIREBASE_INITIALIZED:
        logger.error("_send_system_notification: Firebase not ready.")
        return False
    if not user_id or not message_content:
        logger.warning(f"_send_system_notification: Called with missing user_id or message_content.")
        return False

    # --- Primary Channel: Firebase In-App Notification ---
    firebase_success = False
    notif_id = str(uuid.uuid4())
    notif_data = {
        "message": message_content,
        "type": notif_type,
        "link": link,
        "created_at": datetime.now(timezone.utc).isoformat(),
        "read": False
    }
    try:
        db.reference(f'notifications/{user_id}/{notif_id}', app=db_app).set(notif_data)
        logger.info(f"Firebase notification sent to {user_id}: {message_content[:50]}...")
        firebase_success = True
    except firebase_exceptions.FirebaseError as fe:
        logger.error(f"Failed to send Firebase notification to {user_id} due to Firebase error: {fe}")
    except Exception as e:
        logger.error(f"Failed to send Firebase notification to {user_id} due to generic error: {e}")

    # --- Secondary Channel: Email via Resend ---
    if send_email:
        if not resend.api_key or not SENDER_EMAIL:
            logger.warning(f"Skipping email for user {user_id} because Resend is not configured.")
            return firebase_success # Return status of primary channel

        try:
            user_profile = db.reference(f'users/{user_id}', app=db_app).get()
            if not user_profile or not user_profile.get('email'):
                logger.warning(f"Cannot send email to user {user_id}: no profile or email address found.")
                return firebase_success

            recipient_email = user_profile['email']
            # Basic email validation
            if '@' not in recipient_email or '.' not in recipient_email.split('@')[1]:
                 logger.warning(f"Cannot send email to user {user_id}: invalid email format ('{recipient_email}').")
                 return firebase_success

            # Use message_content as fallback for email body if not provided
            html_content = email_body if email_body else f"<p>{message_content}</p>"
            
            params = {
                "from": SENDER_EMAIL,
                "to": [recipient_email],
                "subject": email_subject or "New Notification from Tunasonga Agri",
                "html": html_content,
            }
            email_response = resend.Emails.send(params)
            logger.info(f"Email dispatched to {recipient_email} via Resend. ID: {email_response['id']}")

        except firebase_exceptions.FirebaseError as fe_db:
            logger.error(f"Email dispatch failed for {user_id}: Could not fetch user profile from Firebase. Error: {fe_db}")
        except Exception as e_resend:
            # This catches errors from the resend.Emails.send() call
            logger.error(f"Email dispatch failed for {user_id} ({recipient_email}). Resend API Error: {e_resend}")

    return firebase_success

#--- Authentication Endpoints ---
@app.route('/api/auth/signup', methods=['POST'])
def signup():
    if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
    uid = None # For error context
    data_req = {} # For error context
    try:
        data_req = request.get_json()
        email, password, name = data_req.get('email'), data_req.get('password'), data_req.get('name')
        phone_number = data_req.get('phone_number')
        if not email or not password or not name: return jsonify({'error': 'Email, password, and name are required'}), 400
        user_record = auth.create_user(email=email, password=password, display_name=name, app=db_app)
        uid = user_record.uid
        user_data = ensure_user_profile_exists(uid, email, name, phone_number)
        if not user_data:
            try: auth.delete_user(uid, app=db_app)
            except Exception as e_del: logger.error(f"Failed to rollback auth user {uid} after DB profile error: {e_del}")
            return jsonify({'error': 'Failed to create user profile in database.'}), 500
        return jsonify({'success': True, 'user': {'uid': uid, **user_data}}), 201
    except auth.EmailAlreadyExistsError: return jsonify({'error': 'Email already exists.'}), 409
    except Exception as e: return handle_route_errors(e, uid_context=f"signup attempt for {data_req.get('email', 'N/A')}")

@app.route('/api/auth/google-signin', methods=['POST'])
def google_signin():
    if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
    uid = None # For error context
    try:
        auth_header = request.headers.get('Authorization', '')
        if not auth_header.startswith('Bearer '): return jsonify({'error': 'Missing or invalid token format for Google Sign-In'}), 401
        id_token = auth_header.split(' ')[1]
        decoded_token = auth.verify_id_token(id_token, app=db_app)
        uid, email, name = decoded_token['uid'], decoded_token.get('email'), decoded_token.get('name')
        user_data = ensure_user_profile_exists(uid, email, name)
        if not user_data: return jsonify({'error': 'Failed to create or retrieve user profile in database.'}), 500
        return jsonify({'success': True, 'user': {'uid': uid, **user_data}}), 200
    except auth.InvalidIdTokenError: return jsonify({'error': 'Invalid ID token from Google.'}), 401
    except Exception as e: return handle_route_errors(e, uid_context=uid)

#--- User Profile Endpoint ---
@app.route('/api/user/profile', methods=['GET', 'PUT'])
def user_profile():
    auth_header = request.headers.get('Authorization')
    uid = None
    try:
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        uid = verify_token(auth_header)
        user_ref = db.reference(f'users/{uid}', app=db_app)
        if request.method == 'GET':
            user_data = user_ref.get()
            if not user_data: return jsonify({'error': 'User profile not found in database.'}), 404
            return jsonify({'uid': uid, **user_data}), 200
        if request.method == 'PUT':
            data = request.get_json()
            update_data = {}
            if 'name' in data: update_data['name'] = data['name']
            if 'location' in data: update_data['location'] = data['location'] # Keep updating legacy text field
            if 'phone_number' in data: update_data['phone_number'] = data['phone_number']

            # --- MODIFIED: Handle new location_coords object ---
            if 'location_coords' in data and isinstance(data['location_coords'], dict):
                lat = data['location_coords'].get('latitude')
                lon = data['location_coords'].get('longitude')
                if isinstance(lat, (int, float)) and isinstance(lon, (int, float)):
                    # Validate coordinate ranges
                    if -90 <= lat <= 90 and -180 <= lon <= 180:
                        update_data['location_coords'] = {'latitude': lat, 'longitude': lon}
                        update_data['geohash'] = _calculate_geohash(lat, lon)
                    else:
                        return jsonify({'error': 'Invalid latitude or longitude values.'}), 400
                else:
                    return jsonify({'error': 'location_coords must contain valid latitude and longitude numbers.'}), 400

            if not update_data: return jsonify({'error': 'No updateable fields provided'}), 400
            user_ref.update(update_data)
            updated_profile = user_ref.get()
            return jsonify({'success': True, 'user': {'uid': uid, **updated_profile}}), 200
    except Exception as e: return handle_route_errors(e, uid_context=uid)

#--- Role Management Endpoints ---
@app.route('/api/user/roles/apply', methods=['POST'])
def apply_for_role():
    auth_header = request.headers.get('Authorization')
    uid = None
    try:
        if not FIREBASE_INITIALIZED or not bucket: return jsonify({'error': 'Server configuration error (Firebase/Storage).'}), 503
        uid = verify_token(auth_header)
        role_applied_for = request.form.get('role')
        if not role_applied_for in ['farmer', 'buyer', 'transporter']: return jsonify({'error': 'Invalid role specified'}), 400
        user_data = db.reference(f'users/{uid}', app=db_app).get()
        if not user_data: return jsonify({'error': 'User profile not found to apply for role.'}), 404
        if user_data.get('roles', {}).get(role_applied_for, False): return jsonify({'error': f'You already have the {role_applied_for} role.'}), 400
        if user_data.get('role_applications', {}).get(role_applied_for) == 'pending': return jsonify({'error': f'Your application for {role_applied_for} is already pending.'}), 400
        application_id = str(uuid.uuid4())
        application_data = {'user_id': uid, 'role': role_applied_for, 'status': 'pending', 'submitted_at': datetime.now(timezone.utc).isoformat(), 'documents': []}
        uploaded_doc_references = {}
        for doc_type_key in request.files:
            file = request.files[doc_type_key]
            if file and file.filename:
                safe_filename = os.path.basename(file.filename)
                filename_in_storage = f"user_documents/{uid}/{role_applied_for}{doc_type_key}{str(uuid.uuid4())}_{safe_filename}"
                blob = bucket.blob(filename_in_storage)
                blob.upload_from_file(file.stream)
                blob.make_public()
                doc_type_clean = doc_type_key.replace('_upload', '')
                application_data['documents'].append({'type': doc_type_clean, 'path': blob.public_url, 'filename': safe_filename})
                uploaded_doc_references[doc_type_clean] = blob.public_url
        db.reference(f'role_applications/{application_id}', app=db_app).set(application_data)
        user_ref = db.reference(f'users/{uid}', app=db_app)
        user_ref.child('role_applications').child(role_applied_for).set('pending')
        if uploaded_doc_references: user_ref.child('document_references').update(uploaded_doc_references)
        return jsonify({'success': True, 'message': f'Application for {role_applied_for} submitted.', 'application_id': application_id}), 201
    except Exception as e: return handle_route_errors(e, uid_context=uid)

#--- Admin Endpoints ---
@app.route('/api/admin/dashboard-stats', methods=['GET'])
def admin_dashboard_stats():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        stats = {
            'total_users': 0, 'users_by_role': {'farmer': 0, 'buyer': 0, 'transporter': 0},
            'pending_role_applications': 0, 'active_listings_produce': 0, 'active_listings_demand': 0,
            'pending_listings': 0, 'active_deals': 0, 'pending_deals_admin_approval': 0,
            'admin_profile': db.reference(f'users/{admin_uid}', app=db_app).get()
        }
        all_users = db.reference('users', app=db_app).get() or {}
        stats['total_users'] = len(all_users)
        for uid_loop, u_data in all_users.items():
            if u_data and u_data.get('roles', {}).get('farmer'): stats['users_by_role']['farmer'] += 1
            if u_data and u_data.get('roles', {}).get('buyer'): stats['users_by_role']['buyer'] += 1
            if u_data and u_data.get('roles', {}).get('transporter'): stats['users_by_role']['transporter'] += 1
        pending_roles_apps = db.reference('role_applications', app=db_app).order_by_child('status').equal_to('pending').get() or {}
        stats['pending_role_applications'] = len(pending_roles_apps)
        all_listings = db.reference('listings', app=db_app).get() or {}
        for lid, ldata in all_listings.items():
            if ldata and ldata.get('status') == 'active':
                if ldata.get('listing_type') == 'produce': stats['active_listings_produce'] += 1
                elif ldata.get('listing_type') == 'demand': stats['active_listings_demand'] += 1
            elif ldata and ldata.get('status') == 'pending_approval': stats['pending_listings'] += 1
        all_deals = db.reference('deals', app=db_app).get() or {}
        for did, ddata in all_deals.items():
            if ddata and ddata.get('status') == 'active': stats['active_deals'] += 1
            elif ddata and ddata.get('status') == 'accepted_by_farmer': stats['pending_deals_admin_approval'] += 1
        return jsonify(stats), 200
    except Exception as e: return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/users', methods=['GET'])
def admin_list_users():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        all_users = db.reference('users', app=db_app).get() or {}
        return jsonify(all_users), 200
    except Exception as e: return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/users/<target_uid>', methods=['GET'])
def admin_get_user(target_uid):
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        user_data = db.reference(f'users/{target_uid}', app=db_app).get()
        if not user_data: return jsonify({'error': 'User not found'}), 404
        return jsonify(user_data), 200
    except Exception as e: return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/users/<target_uid>/update', methods=['POST'])
def admin_update_user(target_uid):
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        data = request.get_json()
        update_payload = {}
        if 'suspended' in data and isinstance(data['suspended'], bool): update_payload['suspended'] = data['suspended']
        if 'is_admin' in data and isinstance(data['is_admin'], bool):
            if target_uid == admin_uid and not data['is_admin']: return jsonify({'error': "Admin cannot remove own admin status."}), 400
            update_payload['is_admin'] = data['is_admin']
        if 'is_facilitator' in data and isinstance(data['is_facilitator'], bool): update_payload['is_facilitator'] = data['is_facilitator']
        if 'roles' in data and isinstance(data['roles'], dict):
            valid_roles = {r: v for r, v in data['roles'].items() if r in ['farmer', 'buyer', 'transporter'] and isinstance(v, bool)}
            if valid_roles: update_payload['roles'] = valid_roles
        if not update_payload: return jsonify({'error': 'No valid fields to update provided'}), 400
        db.reference(f'users/{target_uid}', app=db_app).update(update_payload)
        updated_user = db.reference(f'users/{target_uid}', app=db_app).get()
        return jsonify({'success': True, 'message': f'User {target_uid} updated.', 'user': updated_user}), 200
    except Exception as e: return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/facilitators', methods=['GET'])
def admin_list_facilitators():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        all_users = db.reference('users', app=db_app).order_by_child('is_facilitator').equal_to(True).get() or {}
        return jsonify(all_users), 200
    except Exception as e: return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/users/create', methods=['POST'])
def admin_create_user():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    uid_new_user = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        data = request.get_json()
        email, password, name = data.get('email'), data.get('password'), data.get('name')
        phone_number, is_facilitator_val = data.get('phone_number'), data.get('is_facilitator', False)
        if not email or not password or not name: return jsonify({'error': 'Email, password, and name are required'}), 400
        user_record = auth.create_user(email=email, password=password, display_name=name, app=db_app)
        uid_new_user = user_record.uid
        user_data = ensure_user_profile_exists(uid_new_user, email, name, phone_number)
        if not user_data:
            try: auth.delete_user(uid_new_user, app=db_app)
            except Exception as e_del: logger.error(f"Rollback auth user failed: {e_del}")
            return jsonify({'error': 'Failed to create DB profile.'}), 500
        if is_facilitator_val:
            db.reference(f'users/{uid_new_user}', app=db_app).update({'is_facilitator': True})
            user_data['is_facilitator'] = True
        return jsonify({'success': True, 'message': 'User created by admin.', 'user': {'uid': uid_new_user, **user_data}}), 201
    except auth.EmailAlreadyExistsError: return jsonify({'error': 'Email already exists.'}), 409
    except Exception as e: return handle_route_errors(e, uid_context=admin_uid or uid_new_user)

@app.route('/api/admin/roles/pending', methods=['GET'])
def admin_get_pending_roles():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        apps_ref = db.reference('role_applications', app=db_app).order_by_child('status').equal_to('pending')
        pending_apps = apps_ref.get()
        return jsonify(pending_apps or {}), 200
    except Exception as e: return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/roles/<application_id>/<action>', methods=['POST'])
def admin_action_on_role(application_id, action):
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: 
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        
        if action not in ['approve', 'reject']: 
            return jsonify({'error': 'Invalid action.'}), 400
        
        app_ref = db.reference(f'role_applications/{application_id}', app=db_app)
        application = app_ref.get()
        
        if not application or application.get('status') != 'pending': 
            return jsonify({'error': 'App not found or not pending.'}), 404
        
        user_id = application['user_id']
        role = application['role']
        user_profile_ref = db.reference(f'users/{user_id}', app=db_app)
        update_time = datetime.now(timezone.utc).isoformat()
        message_text = ""
        
        if action == 'approve':
            app_ref.update({'status': 'approved', 'reviewed_by': admin_uid, 'reviewed_at': update_time})
            user_profile_ref.child('roles').update({role: True})
            user_profile_ref.child('role_applications').update({role: 'approved'})
            message_text = f"Role {role} for user {user_id} approved."
            action_past_tense = "approved"
        else:  # reject
            app_ref.update({'status': 'rejected', 'reviewed_by': admin_uid, 'reviewed_at': update_time})
            user_profile_ref.child('role_applications').update({role: 'rejected'})
            message_text = f"Role {role} for user {user_id} rejected."
            action_past_tense = "rejected"

        # --- MODIFIED: Send a rich HTML email for this critical event ---
        email_subject = f"Your Tunasonga Agri Application for the '{role.capitalize()}' Role"
        email_body = f"""
        <div style="font-family: sans-serif; padding: 20px; border: 1px solid #e0e0e0; border-radius: 8px;">
            <h2 style="color: #333;">Application Status Update</h2>
            <p>Hello,</p>
            <p>This is an update regarding your application for the <strong>{role.capitalize()}</strong> role on the Tunasonga platform.</p>
            <p>Your application has been <strong>{action_past_tense}</strong> by an administrator.</p>
            <a href="https://tunasongaagri.co.zw/profile" style="display: inline-block; padding: 10px 15px; background-color: #28a745; color: #ffffff; text-decoration: none; border-radius: 5px; margin-top: 15px;">
                View My Profile
            </a>
            <p style="margin-top: 20px; font-size: 0.9em; color: #777;">
                If you have any questions, please contact our support team.
            </p>
            <p style="margin-top: 5px; font-size: 0.9em; color: #777;">
                Thank you,<br>The Tunasonga Agri Team
            </p>
        </div>
        """
        
        _send_system_notification(
            user_id=user_id, 
            message_content=f"Your application for the '{role}' role has been {action_past_tense}.", 
            notif_type="role_status", 
            link="/profile/roles",
            send_email=True,
            email_subject=email_subject,
            email_body=email_body
        )
        
        return jsonify({'success': True, 'message': message_text}), 200
        
    except Exception as e: 
        return handle_route_errors(e, uid_context=admin_uid)

#--- Marketplace Endpoints ---
# --- MODIFIED: Listing creation now requires coordinates ---
def _create_listing(uid_lister, listing_type, data):
    if not FIREBASE_INITIALIZED: raise ConnectionError("Firebase not ready for listing creation.")
    
    # NEW: location_coords is now a required field, 'location' (text) is optional.
    required_fields = ['crop_type', 'quantity', 'location_coords']
    if listing_type == "produce": required_fields.extend(['asking_price', 'harvest_date'])
    else: required_fields.extend(['quality_specs', 'price_range'])
    if not all(field in data for field in required_fields): raise ValueError(f'Missing fields for {listing_type} listing. Required: {required_fields}')

    # Validate and process coordinates
    location_coords = data.get('location_coords')
    if not isinstance(location_coords, dict) or 'latitude' not in location_coords or 'longitude' not in location_coords:
        raise ValueError('Invalid location_coords object. Must contain latitude and longitude.')
    
    lat = location_coords['latitude']
    lon = location_coords['longitude']
    if not (isinstance(lat, (int, float)) and isinstance(lon, (int, float)) and -90 <= lat <= 90 and -180 <= lon <= 180):
        raise ValueError('Invalid latitude or longitude values in location_coords.')

    listing_id = str(uuid.uuid4())
    listing_data = {
        'lister_id': uid_lister,
        'listing_type': listing_type,
        'status': 'pending_approval',
        'created_at': datetime.now(timezone.utc).isoformat(),
        'geohash': _calculate_geohash(lat, lon), # NEW: Store geohash
        **data
    }
    db.reference(f'listings/{listing_id}', app=db_app).set(listing_data)
    return listing_id, listing_data

@app.route('/api/listings/produce', methods=['POST'])
def create_produce_listing():
    auth_header = request.headers.get('Authorization')
    uid = None
    try:
        uid = verify_role(auth_header, 'farmer')
        listing_id, listing_data = _create_listing(uid, "produce", request.get_json())
        return jsonify({'success': True, 'message': 'Produce listing created, pending approval.', 'listing_id': listing_id}), 201
    except Exception as e: return handle_route_errors(e, uid_context=uid)

@app.route('/api/listings/demand', methods=['POST'])
def create_demand_listing():
    auth_header = request.headers.get('Authorization')
    uid = None
    try:
        uid = verify_role(auth_header, 'buyer')
        listing_id, listing_data = _create_listing(uid, "demand", request.get_json())
        return jsonify({'success': True, 'message': 'Demand listing created, pending approval.', 'listing_id': listing_id}), 201
    except Exception as e: return handle_route_errors(e, uid_context=uid)

@app.route('/api/listings/my', methods=['GET'])
def get_my_listings():
    auth_header = request.headers.get('Authorization')
    uid = None
    try:
        uid = verify_token(auth_header)
        if not FIREBASE_INITIALIZED: 
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        # Get all listings from Firebase
        listings_ref = db.reference('listings', app=db_app)
        all_listings = listings_ref.get()

        if not all_listings or not isinstance(all_listings, dict):
            return jsonify({'success': True, 'listings': []}), 200

        # Filter listings by the authenticated user's UID
        user_listings = []
        for listing_id, listing_data in all_listings.items():
            if isinstance(listing_data, dict) and listing_data.get('lister_id') == uid:
                # Add the listing_id to the listing data for frontend convenience
                listing_data['id'] = listing_id
                user_listings.append(listing_data)

        # Sort by creation date (most recent first) if available
        user_listings.sort(key=lambda x: x.get('created_at', ''), reverse=True)

        return jsonify({
            'success': True, 
            'listings': user_listings,
            'count': len(user_listings)
        }), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=uid)

# MODIFIED: User Update/Remove Own Listing to handle coordinates
@app.route('/api/listings/<listing_id>', methods=['PUT', 'DELETE'])
def user_manage_listing(listing_id):
    auth_header = request.headers.get('Authorization')
    uid = None
    try:
        uid = verify_token(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        listing_ref = db.reference(f'listings/{listing_id}', app=db_app)
        listing_data = listing_ref.get()

        if not listing_data or not isinstance(listing_data, dict):
            return jsonify({'error': 'Listing not found.'}), 404

        if listing_data.get('lister_id') != uid:
            return jsonify({'error': 'Not authorized to manage this listing.'}), 403

        if request.method == 'PUT':
            data = request.get_json()
            update_payload = {}
            requires_reapproval = False

            # Fields that, if changed, require re-approval
            # MODIFIED: 'location_coords' is now a critical field.
            critical_fields = ['crop_type', 'quantity', 'location_coords', 'asking_price', 'harvest_date', 'quality_specs', 'price_range']

            for field in critical_fields:
                if field in data and data[field] != listing_data.get(field):
                    update_payload[field] = data[field]
                    requires_reapproval = True

            # --- MODIFIED: Handle location_coords update and geohash recalculation ---
            if 'location_coords' in update_payload:
                coords = update_payload['location_coords']
                if isinstance(coords, dict) and 'latitude' in coords and 'longitude' in coords:
                    lat, lon = coords['latitude'], coords['longitude']
                    if isinstance(lat, (int, float)) and isinstance(lon, (int, float)):
                        update_payload['geohash'] = _calculate_geohash(lat, lon)
                    else:
                        return jsonify({'error': 'Invalid latitude/longitude in location_coords.'}), 400
                else:
                    return jsonify({'error': 'Invalid location_coords object.'}), 400

            # Allow user to change status to inactive/closed without re-approval
            if 'status' in data and data['status'] in ['inactive', 'closed']:
                update_payload['status'] = data['status']
            elif 'status' in data and data['status'] not in ['inactive', 'closed'] and data['status'] != listing_data.get('status'):
                # If user tries to set to active or pending, force pending_approval if critical fields changed
                if requires_reapproval:
                    update_payload['status'] = 'pending_approval'
                else: # If no critical fields changed, allow status update if valid
                    update_payload['status'] = data['status'] # e.g., from inactive back to active if no critical changes

            if requires_reapproval and update_payload.get('status') != 'pending_approval':
                update_payload['status'] = 'pending_approval' # Ensure pending approval if critical fields changed

            if not update_payload:
                return jsonify({'error': 'No valid fields to update provided or no changes detected.'}), 400

            update_payload['last_updated_at'] = datetime.now(timezone.utc).isoformat()
            listing_ref.update(update_payload)

            message = 'Listing updated successfully.'
            if requires_reapproval:
                message += ' Listing status set to pending_approval due to significant changes.'
                _send_system_notification(uid, f"Your listing for '{listing_data.get('crop_type')}' has been updated and is now pending admin approval.", "listing_status", f"/listings/{listing_id}")
            else:
                _send_system_notification(uid, f"Your listing for '{listing_data.get('crop_type')}' has been updated.", "listing_status", f"/listings/{listing_id}")

            updated_listing = listing_ref.get()
            return jsonify({'success': True, 'message': message, 'listing': updated_listing}), 200

        elif request.method == 'DELETE':
            listing_ref.delete()
            _send_system_notification(uid, f"Your {listing_data.get('listing_type')} listing for '{listing_data.get('crop_type')}' has been removed.", "listing_removed", f"/my-listings")
            return jsonify({'success': True, 'message': 'Listing removed successfully.'}), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=uid)


@app.route('/api/market/<listing_type>', methods=['GET'])
def get_active_listings(listing_type):
    uid_context = "public_market_listings"
    try:
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        if listing_type not in ["produce", "demand"]: return jsonify({'error': 'Invalid listing type'}), 400
        listings_ref = db.reference('listings', app=db_app).order_by_child('status').equal_to('active')
        all_active = listings_ref.get() or {}
        type_filtered = {lid: ldata for lid, ldata in all_active.items() if ldata and ldata.get('listing_type') == listing_type}
        
        # NOTE: The text-based location filter below will only work for legacy data that has the 'location' text field.
        # A proper distance-based filter for all listings would require a more complex implementation.
        crop_filter, loc_filter = request.args.get('crop_type'), request.args.get('location')
        
        final_listings = []
        for lid, ldata in type_filtered.items():
            match = True
            if crop_filter and ldata.get('crop_type', '').lower() != crop_filter.lower(): match = False
            if loc_filter and ldata.get('location', '').lower() != loc_filter.lower(): match = False
            if match: final_listings.append({'id': lid, **ldata})
        return jsonify(final_listings), 200
    except Exception as e: return handle_route_errors(e, uid_context=uid_context)

@app.route('/api/admin/listings/pending', methods=['GET'])
def admin_get_pending_listings():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid, _, _ = verify_admin_or_facilitator(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        listings_ref = db.reference('listings', app=db_app).order_by_child('status').equal_to('pending_approval')
        return jsonify(listings_ref.get() or {}), 200
    except Exception as e: return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/listings/action/<listing_id>', methods=['POST'])
def admin_action_on_listing(listing_id):
    auth_header = request.headers.get('Authorization')
    reviewer_uid = None
    try:
        reviewer_uid, _, _ = verify_admin_or_facilitator(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        data = request.get_json(); action = data.get('action')
        if action not in ['approve', 'reject']: return jsonify({'error': 'Invalid action.'}), 400
        listing_ref = db.reference(f'listings/{listing_id}', app=db_app); listing = listing_ref.get()
        if not listing or listing.get('status') != 'pending_approval': return jsonify({'error': 'Listing not found or not pending.'}), 404
        new_status = 'active' if action == 'approve' else 'rejected'
        listing_ref.update({'status': new_status, 'reviewed_by': reviewer_uid, 'reviewed_at': datetime.now(timezone.utc).isoformat()})
        _send_system_notification(listing.get('lister_id'), f"Your {listing.get('listing_type')} listing for '{listing.get('crop_type')}' has been {new_status}d.", "listing_status", f"/listings/{listing_id}")
        return jsonify({'success': True, 'message': f"Listing {listing_id} {new_status}."}), 200
    except Exception as e: return handle_route_errors(e, uid_context=reviewer_uid)

# NEW: Admin Remove Any Listing
@app.route('/api/admin/listings/<listing_id>/remove', methods=['DELETE'])
def admin_remove_listing(listing_id):
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid, _, _ = verify_admin_or_facilitator(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        listing_ref = db.reference(f'listings/{listing_id}', app=db_app)
        listing_data = listing_ref.get()

        if not listing_data or not isinstance(listing_data, dict):
            return jsonify({'error': 'Listing not found.'}), 404

        lister_id = listing_data.get('lister_id')
        listing_type = listing_data.get('listing_type', 'item')
        crop_type = listing_data.get('crop_type', 'N/A')

        listing_ref.delete()

        if lister_id:
            _send_system_notification(lister_id, f"Your {listing_type} listing for '{crop_type}' (ID: {listing_id}) has been removed by an administrator.", "listing_removed_by_admin", f"/my-listings")

        return jsonify({'success': True, 'message': f'Listing {listing_id} removed by admin/facilitator.'}), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)


#--- Deal Management (MODIFIED SECTION) ---
@app.route('/api/deals/propose', methods=['POST'])
def propose_deal():
    auth_header = request.headers.get('Authorization')
    requester_uid = None # UID of the user making the API call (admin/user)
    acting_uid = None # UID of the user on whose behalf the action is taken

    try:
        logger.info(f"Backend /api/deals/propose received headers: {request.headers}")
        logger.info(f"Backend /api/deals/propose received raw data: {request.get_data(as_text=True)}")

        requester_uid = verify_token(auth_header) # Can raise exceptions
        if not FIREBASE_INITIALIZED:
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        data = request.get_json()
        if not data:
            logger.error("Backend /api/deals/propose: No JSON data received or failed to parse.")
            return jsonify({'error': 'Invalid JSON data received.'}), 400

        on_behalf_of_uid = data.get('on_behalf_of_uid')

        if on_behalf_of_uid:
            # If acting on behalf of someone, verify the requester is an admin/facilitator
            admin_or_facilitator_uid, _, _ = verify_admin_or_facilitator(auth_header) # This will raise if not admin/facilitator
            acting_uid = on_behalf_of_uid
            
            # Verify the user on whose behalf we are acting exists and is a farmer (for WhatsApp farmers)
            acting_user_profile = db.reference(f'users/{acting_uid}', app=db_app).get()
            if not acting_user_profile:
                return jsonify({'error': f'User {acting_uid} (on_behalf_of) not found.'}), 404
            
            # Constraint: WhatsApp farmers can only list produce, so they can only *propose* against demand listings.
            # This means the acting_uid must be a farmer.
            if not acting_user_profile.get('roles', {}).get('farmer') and acting_user_profile.get('account_type') != 'whatsapp_managed':
                return jsonify({'error': f'User {acting_uid} is not a farmer or WhatsApp-managed farmer, cannot propose on their behalf.'}), 403
            
            logger.info(f"Admin/Facilitator {admin_or_facilitator_uid} proposing deal on behalf of {acting_uid}.")
        else:
            acting_uid = requester_uid # Regular user proposing

        listing_id = data.get('listing_id')
        proposed_quantity_by_user = data.get('quantity')
        proposed_price_per_unit_by_user = data.get('price')
        notes = data.get('notes', "")

        logger.info(f"Backend /api/deals/propose: Parsed data - listing_id='{listing_id}', quantity='{proposed_quantity_by_user}', price='{proposed_price_per_unit_by_user}'")

        if not listing_id or proposed_quantity_by_user is None or proposed_price_per_unit_by_user is None:
            logger.error(f"Backend /api/deals/propose: Missing required fields. listing_id: {listing_id}, quantity: {proposed_quantity_by_user}, price: {proposed_price_per_unit_by_user}")
            return jsonify({'error': 'listing_id, quantity, and price are required.'}), 400

        try:
            proposed_quantity_by_user = int(proposed_quantity_by_user)
            proposed_price_per_unit_by_user = float(proposed_price_per_unit_by_user)
            if proposed_quantity_by_user <= 0 or proposed_price_per_unit_by_user <= 0:
                raise ValueError("Quantity and price must be positive numbers.")
        except ValueError as ve:
            logger.error(f"Backend /api/deals/propose: Invalid quantity or price. Error: {str(ve)}")
            return jsonify({'error': f'Invalid quantity or price: {str(ve)}'}), 400

        listing_ref = db.reference(f'listings/{listing_id}', app=db_app)
        listing_data = listing_ref.get()

        if not listing_data or not isinstance(listing_data, dict) or listing_data.get('status') != 'active':
            logger.error(f"Backend /api/deals/propose: Target listing {listing_id} not found, not active, or invalid.")
            return jsonify({'error': 'Target listing not found, not active, or invalid.'}), 404

        original_lister_id = listing_data.get('lister_id')
        listing_type = listing_data.get('listing_type') # 'produce' or 'demand'

        if original_lister_id == acting_uid:
            logger.error(f"Backend /api/deals/propose: User {acting_uid} attempting to deal with own listing {listing_id}.")
            return jsonify({'error': 'Cannot propose a deal to your own listing/demand.'}), 400

        deal_farmer_id = None
        deal_buyer_id = None
        deal_notes_prefix = ""
        notification_recipient_id = original_lister_id # The other party

        if listing_type == 'produce':
            # Current user (proposer acting_uid) is a BUYER, proposing to a FARMER's produce listing.
            # If acting on behalf of a WhatsApp farmer, they cannot be the buyer here.
            if on_behalf_of_uid and acting_user_profile.get('account_type') == 'whatsapp_managed':
                return jsonify({'error': 'WhatsApp farmers can only propose deals as a farmer (against demand listings).'}), 403

            deal_farmer_id = original_lister_id
            deal_buyer_id = acting_uid
            deal_notes_prefix = "Buyer's proposal: "

            available_quantity = listing_data.get('quantity', 0)
            if proposed_quantity_by_user > available_quantity:
                logger.error(f"Backend /api/deals/propose: Proposed quantity {proposed_quantity_by_user} exceeds available {available_quantity} for produce listing {listing_id}.")
                return jsonify({'error': f'Proposed quantity ({proposed_quantity_by_user}) exceeds available quantity ({available_quantity}) for the listing.'}), 400

        elif listing_type == 'demand':
            # Current user (proposer acting_uid) is a FARMER, making an offer against a BUYER's demand listing.
            deal_farmer_id = acting_uid
            deal_buyer_id = original_lister_id
            deal_notes_prefix = "Farmer's offer against demand: "

            # Optional: Check if farmer's offered quantity matches/is within demand's quantity
            # demand_quantity_needed = listing_data.get('quantity', float('inf')) # Assuming demand listing also has 'quantity'
            # if proposed_quantity_by_user > demand_quantity_needed:
            #    logger.error(f"Backend /api/deals/propose: Farmer's offered quantity {proposed_quantity_by_user} exceeds demanded quantity {demand_quantity_needed} for demand {listing_id}.")
            #    return jsonify({'error': f'Your offered quantity ({proposed_quantity_by_user}) exceeds the demanded quantity ({demand_quantity_needed}).'}), 400
        else:
            logger.error(f"Backend /api/deals/propose: Invalid target listing type '{listing_type}' for listing {listing_id}.")
            return jsonify({'error': 'Invalid target listing type for creating a deal.'}), 400

        deal_id = str(uuid.uuid4())
        deal_data_to_set = {
            'deal_id': deal_id,
            'proposer_id': acting_uid, # Use acting_uid here
            'listing_id': listing_id,
            'farmer_id': deal_farmer_id,
            'buyer_id': deal_buyer_id,
            'proposed_quantity': proposed_quantity_by_user,
            'proposed_price': proposed_price_per_unit_by_user, # This is price_per_unit
            'deal_notes': deal_notes_prefix + notes,
            'status': 'proposed',
            'created_at': datetime.now(timezone.utc).isoformat(),
            'chat_room_id': f"deal_{deal_id}"
        }
        # If an admin acted on behalf, record that
        if on_behalf_of_uid:
            deal_data_to_set['proxied_by_admin_uid'] = requester_uid

        db.reference(f'deals/{deal_id}', app=db_app).set(deal_data_to_set)

        _send_system_notification(
            notification_recipient_id,
            f"You have a new proposal/offer from {acting_uid[:6]}... regarding your {listing_type} for '{listing_data.get('crop_type')}'. Qty: {proposed_quantity_by_user}, Price/Unit: {proposed_price_per_unit_by_user}",
            "new_deal_proposal",
            f"/deals/{deal_id}"
        )
        logger.info(f"Backend /api/deals/propose: Deal {deal_id} created successfully by UID {acting_uid} for listing {listing_id}.")
        return jsonify({'success': True, 'message': 'Proposal/Offer submitted successfully.', 'deal': deal_data_to_set}), 201

    except Exception as e:
        # Log the original error before passing to generic handler
        logger.error(f"Backend /api/deals/propose: Unhandled exception for UID {acting_uid or requester_uid or 'unknown'}. Error: {str(e)}\n{traceback.format_exc()}")
        return handle_route_errors(e, uid_context=acting_uid or requester_uid or "propose_deal_unknown_user")

@app.route('/api/deals/<deal_id>/respond', methods=['POST'])
def respond_to_deal(deal_id):
    auth_header = request.headers.get('Authorization')
    requester_uid = None # UID of the user making the API call (admin/user)
    acting_uid = None  # UID of the user on whose behalf the action is taken

    try:
        requester_uid = verify_token(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error'}), 503

        data = request.get_json()
        response_action = data.get('action')  # 'accept' or 'reject'
        on_behalf_of_uid = data.get('on_behalf_of_uid')

        if on_behalf_of_uid:
            # If acting on behalf of someone, verify the requester is an admin/facilitator
            admin_or_facilitator_uid, _, _ = verify_admin_or_facilitator(auth_header) # This will raise if not admin/facilitator
            acting_uid = on_behalf_of_uid

            # Verify the user on whose behalf we are acting exists and is a farmer (for WhatsApp farmers)
            acting_user_profile = db.reference(f'users/{acting_uid}', app=db_app).get()
            if not acting_user_profile:
                return jsonify({'error': f'User {acting_uid} (on_behalf_of) not found.'}), 404

            # Constraint: WhatsApp farmers can only list produce, so they would only *respond* as a farmer.
            if not acting_user_profile.get('roles', {}).get('farmer') and acting_user_profile.get('account_type') != 'whatsapp_managed':
                return jsonify({'error': f'User {acting_uid} is not a farmer or WhatsApp-managed farmer, cannot respond on their behalf.'}), 403

            logger.info(f"Admin/Facilitator {admin_or_facilitator_uid} responding to deal {deal_id} on behalf of {acting_uid}.")
        else:
            acting_uid = requester_uid # Regular user responding

        if response_action not in ['accept', 'reject']:
            return jsonify({'error': 'Invalid action. Must be "accept" or "reject".'}), 400

        deal_ref = db.reference(f'deals/{deal_id}', app=db_app)
        deal_data = deal_ref.get()

        if not deal_data or not isinstance(deal_data, dict):
            return jsonify({'error': 'Deal not found.'}), 404

        current_deal_status = deal_data.get('status')
        proposer_id = deal_data.get('proposer_id')
        farmer_id_in_deal = deal_data.get('farmer_id')
        buyer_id_in_deal = deal_data.get('buyer_id')

        # Authorization Check: Who is allowed to respond?
        can_respond = False
        if current_deal_status == 'proposed':
            if proposer_id == buyer_id_in_deal and acting_uid == farmer_id_in_deal: # Buyer proposed, Farmer responds
                can_respond = True
            elif proposer_id == farmer_id_in_deal and acting_uid == buyer_id_in_deal: # Farmer proposed/countered, Buyer responds
                can_respond = True
        # Add other statuses if a different party needs to respond (e.g., after admin action)

        if not can_respond:
            logger.warning(f"UID {acting_uid} unauthorized to respond to deal {deal_id}. Deal status: {current_deal_status}, Proposer: {proposer_id}, Farmer: {farmer_id_in_deal}, Buyer: {buyer_id_in_deal}")
            return jsonify({'error': 'Not authorized to respond to this deal at its current state.'}), 403

        update_time = datetime.now(timezone.utc).isoformat()

        # Determine the other party for notification
        other_party_id = None
        if acting_uid == farmer_id_in_deal:
            other_party_id = buyer_id_in_deal
        elif acting_uid == buyer_id_in_deal:
            other_party_id = farmer_id_in_deal

        listing_id = deal_data.get('listing_id')
        listing_data_for_notif = {}
        if listing_id:
            listing_data_for_notif = db.reference(f'listings/{listing_id}', app=db_app).get() or {}
        crop_type_for_notif = listing_data_for_notif.get('crop_type', 'your listing/demand')

        update_payload = {}
        if on_behalf_of_uid:
            update_payload['proxied_by_admin_uid'] = requester_uid # Record who proxied the action

        if response_action == 'accept':
            # Quantity check (if applicable, e.g., if responding to a proposal against a produce listing)
            if proposer_id == buyer_id_in_deal and acting_uid == farmer_id_in_deal: # Farmer accepting buyer's proposal
                if listing_id and isinstance(listing_data_for_notif, dict):
                    available_quantity = listing_data_for_notif.get('quantity', 0)
                    proposed_quantity = deal_data.get('proposed_quantity', 0)
                    if proposed_quantity > available_quantity:
                        deal_ref.update({
                            'status': 'rejected_by_system_insufficient_qty',
                            'system_rejection_at': update_time,
                            'system_rejection_reason': f'Listing quantity ({available_quantity}) insufficient for deal quantity ({proposed_quantity}) at time of acceptance.'
                        })
                        if other_party_id:
                            _send_system_notification(other_party_id, f"Your deal proposal for '{crop_type_for_notif}' could not be accepted due to insufficient stock.", "deal_status_update", f"/deals/{deal_id}")
                        return jsonify({'success': False, 'error': 'Deal could not be accepted. Listing quantity is no longer sufficient.'}), 409

            accepted_by_field = ""
            new_status = ""
            if acting_uid == farmer_id_in_deal:
                accepted_by_field = "farmer_accepted_at"
                new_status = "accepted_by_farmer" # Farmer accepts buyer's proposal
                notification_message_to_other_party = f"Your deal proposal for '{crop_type_for_notif}' has been ACCEPTED by the farmer. It is now pending admin approval."
            elif acting_uid == buyer_id_in_deal:
                accepted_by_field = "buyer_accepted_at"
                new_status = "accepted_by_buyer" # Buyer accepts farmer's offer/counter
                notification_message_to_other_party = f"Your offer/counter-offer for '{crop_type_for_notif}' has been ACCEPTED by the buyer. It is now pending admin approval."
            else: # Should not happen due to auth check
                return jsonify({'error': 'Internal error determining accepter role.'}), 500

            update_payload.update({'status': new_status, accepted_by_field: update_time, 'last_responder_id': acting_uid})
            deal_ref.update(update_payload)

            if other_party_id:
                _send_system_notification(other_party_id, notification_message_to_other_party, "deal_status_update", f"/deals/{deal_id}")

            # Notify admins
            admins_ref = db.reference('users', app=db_app).order_by_child('is_admin').equal_to(True).get()
            if admins_ref:
                for admin_id_loop, _ in admins_ref.items():
                     _send_system_notification(admin_id_loop, f"Deal ID {deal_id} for '{crop_type_for_notif}' has been accepted by {acting_uid[:6]}... and needs your approval.", "admin_deal_approval_needed", f"/admin/deals/pending") # Path for admin to see pending deals

            return jsonify({'success': True, 'message': f'Deal accepted by {("farmer" if acting_uid == farmer_id_in_deal else "buyer")}, pending admin approval.'}), 200

        elif response_action == 'reject':
            rejected_by_field = ""
            new_status = ""
            if acting_uid == farmer_id_in_deal:
                rejected_by_field = "farmer_rejected_at" # Or just 'responded_at'
                new_status = "rejected_by_farmer"
                notification_message_to_other_party = f"Your deal proposal for '{crop_type_for_notif}' has been REJECTED by the farmer."
            elif acting_uid == buyer_id_in_deal:
                rejected_by_field = "buyer_rejected_at"
                new_status = "rejected_by_buyer"
                notification_message_to_other_party = f"Your offer/counter-offer for '{crop_type_for_notif}' has been REJECTED by the buyer."
            else: # Should not happen
                return jsonify({'error': 'Internal error determining rejector role.'}), 500

            update_payload.update({'status': new_status, rejected_by_field: update_time, 'last_responder_id': acting_uid})
            deal_ref.update(update_payload)
            if other_party_id:
                _send_system_notification(other_party_id, notification_message_to_other_party, "deal_status_update", f"/deals/{deal_id}")
            return jsonify({'success': True, 'message': f'Deal rejected by {("farmer" if acting_uid == farmer_id_in_deal else "buyer")}.'}), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=acting_uid or requester_uid)

@app.route('/api/deals/<deal_id>/complete', methods=['POST'])
def complete_deal_by_admin(deal_id):
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error'}), 503

        deal_ref = db.reference(f'deals/{deal_id}', app=db_app)
        deal_data = deal_ref.get()

        if not deal_data or not isinstance(deal_data, dict):
            return jsonify({'error': 'Deal not found.'}), 404

        if deal_data.get('status') != 'active':
            if not (deal_data.get('status') == 'active' and deal_data.get('transport_status') in ['transporter_accepted', 'in_transit', 'transport_completed', None]):
                 return jsonify({'error': f"Deal cannot be completed by admin from current status: '{deal_data.get('status')}' / transport: '{deal_data.get('transport_status')}'."}), 400

        listing_id = deal_data.get('listing_id')
        deal_quantity = deal_data.get('proposed_quantity', 0)

        if not listing_id or not isinstance(deal_quantity, (int, float)) or deal_quantity <= 0:
            return jsonify({'error': 'Deal data is incomplete (missing listing_id or invalid quantity). Cannot complete.'}), 400

        listing_ref = db.reference(f'listings/{listing_id}', app=db_app)

        def update_listing_transaction(current_listing_data_tx):
            if not current_listing_data_tx or not isinstance(current_listing_data_tx, dict):
                logger.error(f"CompleteDealByAdmin: Listing {listing_id} not found or malformed during transaction for deal {deal_id}.")
                return current_listing_data_tx

            current_listing_quantity = current_listing_data_tx.get('quantity', 0)
            new_listing_quantity = current_listing_quantity - deal_quantity

            updates = {}
            if new_listing_quantity <= 0:
                updates['quantity'] = 0
                updates['status'] = 'closed'
            else:
                updates['quantity'] = new_listing_quantity

            current_listing_data_tx.update(updates)
            return current_listing_data_tx

        transaction_result = listing_ref.transaction(update_listing_transaction)

        if transaction_result is None and listing_ref.get() is not None :
            logger.warning(f"CompleteDealByAdmin: Transaction to update listing {listing_id} for deal {deal_id} was aborted or listing became null. Deal will be marked complete, but listing quantity may not be updated.")
        elif listing_ref.get() is None:
             logger.warning(f"CompleteDealByAdmin: Listing {listing_id} not found for deal {deal_id}. Deal will be marked complete, but listing quantity not updated.")
        else:
            logger.info(f"Deal {deal_id} completion: Listing {listing_id} quantity updated via transaction.")

        deal_updates = {
            'status': 'completed',
            'completed_at': datetime.now(timezone.utc).isoformat(),
            'completed_by': admin_uid
        }
        if deal_data.get('assigned_transporter_id'):
            deal_updates['transport_status'] = 'transport_completed'

        deal_ref.update(deal_updates)

        farmer_id = deal_data.get('farmer_id')
        buyer_id = deal_data.get('buyer_id')
        transporter_id = deal_data.get('assigned_transporter_id')

        listing_data_for_notif = db.reference(f'listings/{listing_id}', app=db_app).get() or {}
        crop_type_for_notif = listing_data_for_notif.get('crop_type', 'your item')

        if farmer_id:
            _send_system_notification(farmer_id, f"Admin has marked deal {deal_id} for '{crop_type_for_notif}' as COMPLETED.", "deal_completed_by_admin", f"/deals/{deal_id}")
        if buyer_id:
            _send_system_notification(buyer_id, f"Admin has marked deal {deal_id} for '{crop_type_for_notif}' as COMPLETED.", "deal_completed_by_admin", f"/deals/{deal_id}")
        if transporter_id and deal_data.get('assigned_transporter_id'):
            _send_system_notification(transporter_id, f"Admin has marked transport job for deal {deal_id} as COMPLETED.", "transport_job_completed_by_admin", f"/transporter/jobs/{deal_id}")

        return jsonify({'success': True, 'message': f'Deal {deal_id} marked as completed by admin. Listing quantity updated (if applicable).'}), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/deals/my', methods=['GET'])
def get_my_deals():
    auth_header = request.headers.get('Authorization')
    uid = None
    try:
        if not FIREBASE_INITIALIZED:
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        uid = verify_token(auth_header)
        if not uid:
             return jsonify({'error': 'Invalid or expired token / verification failed.'}), 401

        all_deals_ref = db.reference('deals', app=db_app)
        all_deals = all_deals_ref.get()

        my_deals = {}
        if all_deals:
            for deal_id, deal_data_loop in all_deals.items():
                if isinstance(deal_data_loop, dict) and \
                   (deal_data_loop.get('buyer_id') == uid or \
                    deal_data_loop.get('farmer_id') == uid or \
                    deal_data_loop.get('assigned_transporter_id') == uid):
                    deal_data_with_id = deal_data_loop.copy()
                    deal_data_with_id['deal_id'] = deal_id
                    my_deals[deal_id] = deal_data_with_id

        return jsonify(my_deals), 200

    except Exception as e_auth_related:
        return handle_route_errors(e_auth_related, uid_context=uid)

# NEW: Admin Remove Any Deal
@app.route('/api/admin/deals/<deal_id>/remove', methods=['DELETE'])
def admin_remove_deal(deal_id):
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid, _, _ = verify_admin_or_facilitator(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        deal_ref = db.reference(f'deals/{deal_id}', app=db_app)
        deal_data = deal_ref.get()

        if not deal_data or not isinstance(deal_data, dict):
            return jsonify({'error': 'Deal not found.'}), 404

        farmer_id = deal_data.get('farmer_id')
        buyer_id = deal_data.get('buyer_id')
        transporter_id = deal_data.get('assigned_transporter_id')
        listing_id = deal_data.get('listing_id')

        crop_type = "N/A"
        if listing_id:
            listing_details = db.reference(f'listings/{listing_id}', app=db_app).get()
            if listing_details:
                crop_type = listing_details.get('crop_type', 'N/A')

        deal_ref.delete()

        message_to_parties = f"Deal ID {deal_id} for '{crop_type}' has been removed by an administrator."
        if farmer_id:
            _send_system_notification(farmer_id, message_to_parties, "deal_removed_by_admin", f"/my-deals")
        if buyer_id:
            _send_system_notification(buyer_id, message_to_parties, "deal_removed_by_admin", f"/my-deals")
        if transporter_id:
            _send_system_notification(transporter_id, f"Your transport job for deal {deal_id} has been cancelled by an administrator.", "transport_job_cancelled_by_admin", f"/transporter/jobs")

        return jsonify({'success': True, 'message': f'Deal {deal_id} removed by admin/facilitator.'}), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)

# Removed the admin_create_manual_deal endpoint as its functionality is now integrated into propose_deal and respond_to_deal.


#--- END OF MODIFIED DEAL MANAGEMENT SECTION ---
#--- TRANSPORTER ENDPOINTS (NEW BLOCK) ---

# --- NEW: Find Nearest Transporters Endpoint ---
@app.route('/api/transporters/find-nearest', methods=['POST'])
def find_nearest_transporters():
    auth_header = request.headers.get('Authorization')
    uid = None
    try:
        # Any authenticated user can find transporters
        uid = verify_token(auth_header)
        if not FIREBASE_INITIALIZED:
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        data = request.get_json()
        lat = data.get('latitude')
        lon = data.get('longitude')
        radius_km = data.get('radius_km', 50) # Default search radius of 50km

        if not isinstance(lat, (int, float)) or not isinstance(lon, (int, float)):
            return jsonify({'error': 'Valid latitude and longitude are required.'}), 400
        if not (isinstance(radius_km, (int, float)) and radius_km > 0):
            return jsonify({'error': 'A valid, positive search radius (radius_km) is required.'}), 400

        origin_coords = {'latitude': lat, 'longitude': lon}
        
        # 1. Get the 9-box geohash query area
        geohash_area_to_query = _get_geohash_query_area(lat, lon)
        
        candidate_transporters = {} # Use dict to avoid duplicates

        # 2. Query Firebase for each geohash box
        # NOTE: This performs 9 separate queries. For very high traffic,
        # a more advanced data structure/service might be needed.
        for gh in geohash_area_to_query:
            # Query users by geohash. Indexing '.indexOn": ["geohash"]' in Firebase rules for 'users' is critical for performance.
            query_results = db.reference('users', app=db_app).order_by_child('geohash').equal_to(gh).get()
            if query_results:
                for user_id, user_data in query_results.items():
                    # 3. Filter for actual transporters with valid coordinates
                    if user_data and user_data.get('roles', {}).get('transporter') and user_data.get('location_coords'):
                        candidate_transporters[user_id] = user_data
        
        # 4. Perform precise distance calculation and filtering
        transporters_in_radius = []
        for user_id, user_data in candidate_transporters.items():
            distance = _calculate_distance(origin_coords, user_data['location_coords'])
            if distance <= radius_km:
                # Add distance to the user data before returning
                user_data_with_dist = user_data.copy()
                user_data_with_dist['uid'] = user_id
                user_data_with_dist['distance_km'] = round(distance, 2)
                transporters_in_radius.append(user_data_with_dist)

        # 5. Sort the final list by distance
        transporters_in_radius.sort(key=lambda x: x['distance_km'])

        return jsonify(transporters_in_radius), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=uid)

@app.route('/api/admin/deals/<deal_id>/assign-transporter', methods=['POST'])
def admin_assign_transporter(deal_id):
    auth_header = request.headers.get('Authorization')
    reviewer_uid = None
    try:
        reviewer_uid, _, _ = verify_admin_or_facilitator(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        data = request.get_json()
        transporter_id = data.get('transporter_id')
        initial_offer_amount = data.get('initial_offer_amount')
        initial_currency = data.get('initial_currency', 'USD')
        proposed_pickup_date = data.get('proposed_pickup_date')
        notes_for_transporter = data.get('notes_for_transporter', "")

        if not transporter_id or initial_offer_amount is None or not proposed_pickup_date:
            return jsonify({'error': 'transporter_id, initial_offer_amount, and proposed_pickup_date are required.'}), 400

        try:
            initial_offer_amount = float(initial_offer_amount)
        except ValueError:
            return jsonify({'error': 'initial_offer_amount must be a valid number.'}), 400

        deal_ref = db.reference(f'deals/{deal_id}', app=db_app)
        deal_data = deal_ref.get()

        if not deal_data:
            return jsonify({'error': 'Deal not found.'}), 404

        if deal_data.get('status') != 'active': # Only assign transport to active deals
            return jsonify({'error': f"Deal is not active. Current status: {deal_data.get('status')}"}), 400

        transporter_profile_ref = db.reference(f'users/{transporter_id}', app=db_app)
        transporter_profile = transporter_profile_ref.get()
        if not transporter_profile or not transporter_profile.get('roles', {}).get('transporter'):
            return jsonify({'error': 'Invalid transporter ID or user is not a transporter.'}), 400

        transport_offer_details = {
            "amount": initial_offer_amount,
            "currency": initial_currency,
            "pickup_date_proposed": proposed_pickup_date,
            "delivery_date_proposed": data.get("proposed_delivery_date", ""),
            "notes": notes_for_transporter,
            "offered_by": "admin", # Or reviewer_uid for more specific tracking
            "offer_timestamp": datetime.now(timezone.utc).isoformat()
        }

        update_payload = {
            'assigned_transporter_id': transporter_id,
            'transport_status': 'assigned', # Job is now assigned to the transporter
            'transport_offer': transport_offer_details,
            'last_transport_update_by': reviewer_uid,
            'last_transport_update_at': datetime.now(timezone.utc).isoformat()
        }

        history_entry_key = db.reference(f'deals/{deal_id}/transport_job_history', app=db_app).push().key
        history_entry = {
            "action": "assigned_to_transporter",
            "user_id": reviewer_uid, # Admin/Facilitator who assigned
            "transporter_id": transporter_id,
            "offer": transport_offer_details,
            "timestamp": datetime.now(timezone.utc).isoformat()
        }
        update_payload[f'transport_job_history/{history_entry_key}'] = history_entry

        deal_ref.update(update_payload)

        # Denormalize for transporter's easy query
        transporter_job_summary = {
            'deal_id': deal_id,
            'farmer_id': deal_data.get('farmer_id'),
            'buyer_id': deal_data.get('buyer_id'),
            'listing_id': deal_data.get('listing_id'),
            'transport_status': 'assigned',
            'assigned_at': datetime.now(timezone.utc).isoformat(),
            'offer': transport_offer_details
            # Add other relevant summary fields from the deal if needed
        }
        db.reference(f'transporter_jobs/{transporter_id}/{deal_id}', app=db_app).set(transporter_job_summary)


        _send_system_notification(
            transporter_id,
            f"You have been assigned a new transport job for deal ID: {deal_id}. Please review and respond.",
            "new_transport_job",
            f"/transporter/jobs/{deal_id}" # Example link for frontend
        )

        return jsonify({'success': True, 'message': f'Transport job for deal {deal_id} assigned to transporter {transporter_id}.'}), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=reviewer_uid)

@app.route('/api/transporter/jobs/pending', methods=['GET'])
def transporter_get_pending_jobs():
    auth_header = request.headers.get('Authorization')
    transporter_uid = None
    try:
        transporter_uid = verify_role(auth_header, 'transporter')
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        # Querying denormalized transporter_jobs for efficiency
        pending_jobs_ref = db.reference(f'transporter_jobs/{transporter_uid}', app=db_app)\
                             .order_by_child('transport_status')\
                             .equal_to('assigned')
        pending_jobs_data = pending_jobs_ref.get() or {}

        # If you need full deal details, you might fetch them based on deal_id from pending_jobs_data
        # For now, returning the summary stored in transporter_jobs
        return jsonify(pending_jobs_data), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=transporter_uid)

@app.route('/api/transporter/deals/<deal_id>/job-action', methods=['POST'])
def transporter_job_action(deal_id):
    auth_header = request.headers.get('Authorization')
    transporter_uid = None
    try:
        transporter_uid = verify_role(auth_header, 'transporter')
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        data = request.get_json()
        action = data.get('action') # "accept", "reject", "counter_offer"

        deal_ref = db.reference(f'deals/{deal_id}', app=db_app)
        deal_data = deal_ref.get()

        if not deal_data or not isinstance(deal_data, dict):
            return jsonify({'error': 'Deal (transport job) not found.'}), 404

        if deal_data.get('assigned_transporter_id') != transporter_uid:
            return jsonify({'error': 'You are not assigned to this transport job.'}), 403

        current_transport_status = deal_data.get('transport_status')

        update_payload = {
            'last_transport_update_by': transporter_uid,
            'last_transport_update_at': datetime.now(timezone.utc).isoformat()
        }
        history_action_type = ""
        notification_message_to_admin = ""
        new_transport_status = "" # Will hold the new status for the deal and transporter_jobs

        if action == "accept":
            if current_transport_status != 'assigned' and current_transport_status != 'admin_reoffered': # Assuming admin can re-offer
                return jsonify({'error': f'Job cannot be accepted from current status: {current_transport_status}'}), 400

            new_transport_status = 'transporter_accepted'
            update_payload['transport_status'] = new_transport_status
            update_payload['transport_offer_accepted_at'] = datetime.now(timezone.utc).isoformat()
            if data.get("acceptance_notes"): # Store notes if provided
                update_payload['transport_acceptance_notes'] = data.get("acceptance_notes")

            history_action_type = "job_accepted"
            notification_message_to_admin = f"Transporter {transporter_uid[:6]}... has ACCEPTED the transport job for deal {deal_id}."

        elif action == "reject":
            if current_transport_status not in ['assigned', 'admin_reoffered', 'admin_rejected_counter']: # Transporter can reject if assigned, or if admin rejected their counter
                 return jsonify({'error': f'Job cannot be rejected from current status: {current_transport_status}'}), 400

            rejection_reason = data.get('rejection_reason', 'No reason provided.')
            new_transport_status = 'transporter_rejected'
            update_payload['transport_status'] = new_transport_status
            update_payload['transport_rejection_reason'] = rejection_reason
            # Admin will need to re-assign. Consider if assigned_transporter_id should be nulled here or by admin.

            history_action_type = "job_rejected"
            notification_message_to_admin = f"Transporter {transporter_uid[:6]}... has REJECTED the transport job for deal {deal_id}. Reason: {rejection_reason}"


        elif action == "counter_offer":
            # Can counter if initially 'assigned' or if admin 'admin_rejected_counter' to their previous counter
            if current_transport_status not in ['assigned', 'admin_rejected_counter']:
                return jsonify({'error': f'Cannot make counter-offer from current status: {current_transport_status}'}), 400

            counter_amount = data.get('counter_offer_amount')
            counter_currency = data.get('currency', deal_data.get('transport_offer', {}).get('currency', 'USD'))
            counter_pickup_date = data.get('proposed_pickup_date', deal_data.get('transport_offer', {}).get('pickup_date_proposed'))
            counter_delivery_date = data.get('proposed_delivery_date', deal_data.get('transport_offer', {}).get('delivery_date_proposed', ""))
            counter_notes = data.get('notes', "")

            if counter_amount is None:
                return jsonify({'error': 'counter_offer_amount is required for a counter-offer.'}), 400
            try: counter_amount = float(counter_amount)
            except ValueError: return jsonify({'error': 'counter_offer_amount must be a number.'}), 400

            new_transport_status = 'transporter_counter_offer'
            update_payload['transport_status'] = new_transport_status
            update_payload['transport_offer'] = { # This becomes the new current offer
                "amount": counter_amount,
                "currency": counter_currency,
                "pickup_date_proposed": counter_pickup_date,
                "delivery_date_proposed": counter_delivery_date,
                "notes": counter_notes,
                "offered_by": "transporter",
                "offer_timestamp": datetime.now(timezone.utc).isoformat()
            }
            history_action_type = "job_counter_offered"
            notification_message_to_admin = f"Transporter {transporter_uid[:6]}... has made a COUNTER-OFFER for the transport job on deal {deal_id}."

        else:
            return jsonify({'error': 'Invalid action specified. Must be "accept", "reject", or "counter_offer".'}), 400

        # Log history within the deal
        history_entry_key = db.reference(f'deals/{deal_id}/transport_job_history', app=db_app).push().key
        history_entry_data = {
            "action": history_action_type,
            "user_id": transporter_uid, # The transporter performing the action
            "timestamp": datetime.now(timezone.utc).isoformat(),
        }
        if action == "counter_offer": history_entry_data["offer_details"] = update_payload['transport_offer']
        if action == "reject": history_entry_data["reason"] = rejection_reason
        if action == "accept" and data.get("acceptance_notes"): history_entry_data["notes"] = data.get("acceptance_notes")

        update_payload[f'transport_job_history/{history_entry_key}'] = history_entry_data

        deal_ref.update(update_payload)

        # Notify Admin/Facilitator
        admins_ref = db.reference('users', app=db_app).order_by_child('is_admin').equal_to(True).get()
        if admins_ref:
            for admin_id_loop, _ in admins_ref.items(): # Renamed admin_id
                _send_system_notification(admin_id_loop, notification_message_to_admin, "transport_job_update", f"/admin/deals/{deal_id}")

        # Update denormalized transporter_jobs summary
        transporter_job_ref = db.reference(f'transporter_jobs/{transporter_uid}/{deal_id}', app=db_app)
        if transporter_job_ref.get(): # Check if summary exists
            transporter_job_ref.update({
                'transport_status': new_transport_status,
                'last_action_at': datetime.now(timezone.utc).isoformat(),
                'offer': update_payload.get('transport_offer', deal_data.get('transport_offer'))
            })

        return jsonify({'success': True, 'message': f'Transport job action "{action}" processed successfully.'}), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=transporter_uid)

@app.route('/api/admin/deals/<deal_id>/respond-to-counter-offer', methods=['POST'])
def admin_respond_to_transporter_counter(deal_id):
    auth_header = request.headers.get('Authorization')
    reviewer_uid = None
    try:
        reviewer_uid, _, _ = verify_admin_or_facilitator(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        data = request.get_json()
        action = data.get('action') # "accept_counter" or "reject_counter"
        notes = data.get('notes', "")

        if action not in ["accept_counter", "reject_counter"]:
            return jsonify({'error': 'Invalid action. Must be "accept_counter" or "reject_counter".'}), 400

        deal_ref = db.reference(f'deals/{deal_id}', app=db_app)
        deal_data = deal_ref.get()

        if not deal_data or not isinstance(deal_data, dict):
            return jsonify({'error': 'Deal not found.'}), 404

        if deal_data.get('transport_status') != 'transporter_counter_offer':
            return jsonify({'error': 'Deal is not in "transporter_counter_offer" status.'}), 400

        transporter_id = deal_data.get('assigned_transporter_id')
        if not transporter_id: # Should not happen if status is transporter_counter_offer
            return jsonify({'error': 'No transporter assigned to this deal for counter-offer response.'}), 400

        update_payload = {
            'last_transport_update_by': reviewer_uid,
            'last_transport_update_at': datetime.now(timezone.utc).isoformat()
        }
        history_action_type = ""
        notification_message_to_transporter = ""
        new_transport_status = ""

        if action == "accept_counter":
            new_transport_status = 'transporter_accepted' # The counter offer becomes the accepted offer
            update_payload['transport_status'] = new_transport_status
            update_payload['transport_offer_finalized_at'] = datetime.now(timezone.utc).isoformat()
            # The current deal_data['transport_offer'] is the transporter's counter, which is now accepted.
            history_action_type = "admin_accepted_counter"
            notification_message_to_transporter = f"Your counter-offer for transport on deal {deal_id} has been ACCEPTED by admin."

        elif action == "reject_counter":
            new_transport_status = 'admin_rejected_counter'
            update_payload['transport_status'] = new_transport_status
            if notes: update_payload['admin_rejection_notes_to_transporter'] = notes # Store admin notes
            history_action_type = "admin_rejected_counter"
            notification_message_to_transporter = f"Your counter-offer for transport on deal {deal_id} has been REJECTED by admin. {notes}"
            # Transporter might be able to make another counter, or admin might re-assign.

        # Log history
        history_entry_key = db.reference(f'deals/{deal_id}/transport_job_history', app=db_app).push().key
        history_entry_data = {
            "action": history_action_type,
            "user_id": reviewer_uid, # Admin/Facilitator
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "notes": notes
        }
        update_payload[f'transport_job_history/{history_entry_key}'] = history_entry_data

        deal_ref.update(update_payload)

        _send_system_notification(transporter_id, notification_message_to_transporter, "transport_job_update", f"/transporter/jobs/{deal_id}")

        # Update denormalized transporter_jobs summary
        transporter_job_ref = db.reference(f'transporter_jobs/{transporter_id}/{deal_id}', app=db_app)
        if transporter_job_ref.get():
            transporter_job_ref.update({
                'transport_status': new_transport_status,
                'last_action_at': datetime.now(timezone.utc).isoformat()
                # Offer details remain as the transporter's last counter offer, which was accepted/rejected
            })

        return jsonify({'success': True, 'message': f'Response to transporter counter-offer processed: {action}.'}), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=reviewer_uid)

#--- END OF TRANSPORTER ENDPOINTS ---
#--- ADMIN ENDPOINTS FOR ALL LISTINGS/DEALS (NEW BLOCK) ---
@app.route('/api/admin/listings/all', methods=['GET'])
def admin_get_all_listings():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED:
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        listings_ref = db.reference('listings', app=db_app)
        all_listings = listings_ref.get() or {}

        return jsonify(all_listings), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/deals/all', methods=['GET'])
def admin_get_all_deals():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED:
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        deals_ref = db.reference('deals', app=db_app)
        all_deals = deals_ref.get() or {}

        return jsonify(all_deals), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)

#--- END OF ADMIN ALL LISTINGS/DEALS ---
#--- ADMIN ENDPOINTS FOR WHATSAPP-MANAGED FARMER ACCOUNTS ---
@app.route('/api/admin/whatsapp-farmers/create', methods=['POST'])
def admin_create_whatsapp_farmer():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED:
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        data = request.get_json()
        name = data.get('name')
        phone_number = data.get('phone_number') # Expecting E.164 format ideally
        location = data.get('location', "")
        initial_notes = data.get('initial_notes', "")

        if not name or not phone_number:
            return jsonify({'error': 'Farmer name and phone number are required.'}), 400

        # Basic validation for phone number format (can be enhanced)
        if not re.match(r"^\+?[1-9]\d{1,14}$", phone_number):
            return jsonify({'error': 'Invalid phone number format. Please use E.164 like +263771234567.'}), 400

        # Check if phone number is already in use by a fully registered webapp user
        # This query can be slow if you have many users. Consider indexing phone_number.
        users_ref = db.reference('users', app=db_app)
        existing_user_query = users_ref.order_by_child('phone_number').equal_to(phone_number).limit_to_first(1).get()
        if existing_user_query:
            for existing_uid, existing_user_data in existing_user_query.items():
                if existing_user_data.get('account_type') == 'webapp_registered':
                    return jsonify({'error': f'This phone number is already registered to a web app user (UID: {existing_uid}).'}), 409
                # Optionally, handle if already a whatsapp_managed account with this number
                # if existing_user_data.get('account_type') == 'whatsapp_managed':
                #    return jsonify({'error': f'This phone number is already managed for another WhatsApp farmer (UID: {existing_uid}).'}), 409


        # Generate a unique ID for this WhatsApp-managed farmer
        # This UID will be used in the 'users' node. No Firebase Auth user created at this stage.
        farmer_uid = f"wpfarmer_{str(uuid.uuid4())}"

        profile_data = {
            'uid': farmer_uid, # Store the UID within the profile too for convenience
            'name': name,
            'phone_number': phone_number,
            'email': f"{farmer_uid}@whatsapp.tunasonga.internal", # Placeholder email
            'location': location,
            'roles': {'farmer': True, 'buyer': False, 'transporter': False},
            'account_type': "whatsapp_managed",
            'is_placeholder_account': True, # Indicates this was admin-created before web registration
            'can_login_webapp': False, # Cannot log in to web app yet
            'managed_by_admin_uid': admin_uid,
            'created_at': datetime.now(timezone.utc).isoformat(),
            'created_by_admin_uid': admin_uid, # Explicitly track creator
            'whatsapp_interaction_log': [{ # Start a log
                'timestamp': datetime.now(timezone.utc).isoformat(),
                'action': 'account_created_by_admin',
                'admin_uid': admin_uid,
                'notes': f"Initial notes: {initial_notes}" if initial_notes else "Account created."
            }]
        }

        db.reference(f'users/{farmer_uid}', app=db_app).set(profile_data)

        return jsonify({
            'success': True,
            'message': f'WhatsApp-managed farmer account created for {name} ({phone_number}).',
            'farmer_uid': farmer_uid,
            'profile': profile_data
        }), 201

    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/whatsapp-farmers', methods=['GET'])
def admin_list_whatsapp_farmers():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED:
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        users_ref = db.reference('users', app=db_app)
        # Querying for account_type. This requires an index on 'account_type' in Firebase rules for performance.
        # ".indexOn": ["account_type"] under your "users" rules.
        whatsapp_farmers_query = users_ref.order_by_child('account_type').equal_to('whatsapp_managed').get()

        whatsapp_farmers = whatsapp_farmers_query or {}

        return jsonify(whatsapp_farmers), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/whatsapp-farmers/<farmer_uid>', methods=['GET'])
def admin_get_whatsapp_farmer(farmer_uid):
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED:
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        farmer_ref = db.reference(f'users/{farmer_uid}', app=db_app)
        farmer_data = farmer_ref.get()

        if not farmer_data or farmer_data.get('account_type') != 'whatsapp_managed':
            return jsonify({'error': 'WhatsApp-managed farmer not found or not of correct type.'}), 404

        return jsonify(farmer_data), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/whatsapp-farmers/<farmer_uid>/update', methods=['PUT'])
def admin_update_whatsapp_farmer(farmer_uid):
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED:
            return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503

        farmer_ref = db.reference(f'users/{farmer_uid}', app=db_app)
        farmer_data = farmer_ref.get()

        if not farmer_data or farmer_data.get('account_type') != 'whatsapp_managed':
            return jsonify({'error': 'WhatsApp-managed farmer not found or not of correct type.'}), 404

        data = request.get_json()
        updates = {}
        allowed_fields_to_update = ['name', 'location', 'phone_number'] # Define what admin can change

        for field in allowed_fields_to_update:
            if field in data:
                updates[field] = data[field]

        if not updates and 'additional_notes' not in data : # Check if any valid fields or notes are provided
             return jsonify({'error': 'No valid fields to update or notes provided.'}), 400

        # Log the update action
        if data.get('additional_notes'):
            log_entry_key = db.reference(f'users/{farmer_uid}/whatsapp_interaction_log', app=db_app).push().key
            log_entry = {
                'timestamp': datetime.now(timezone.utc).isoformat(),
                'action': 'admin_update_notes',
                'admin_uid': admin_uid,
                'notes': data.get('additional_notes')
            }
            # To add to the log, we need to fetch existing logs or use a transaction if it's critical
            # For simplicity here, we'll just push a new entry.
            # If you want to update the main profile and add a log entry atomically,
            # you'd construct a single update payload for farmer_ref.update()
            db.reference(f'users/{farmer_uid}/whatsapp_interaction_log/{log_entry_key}', app=db_app).set(log_entry)


        if updates: # If there are profile fields to update
            updates['last_updated_by_admin_uid'] = admin_uid
            updates['last_updated_at'] = datetime.now(timezone.utc).isoformat()
            farmer_ref.update(updates)

        updated_farmer_data = farmer_ref.get() # Get the latest data

        return jsonify({
            'success': True,
            'message': f'WhatsApp-managed farmer {farmer_uid} updated.',
            'profile': updated_farmer_data
        }), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)

#--- END OF WHATSAPP-MANAGED FARMER ACCOUNT ENDPOINTS ---
@app.route('/api/admin/deals/pending', methods=['GET'])
def admin_get_pending_deals():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid, _, _ = verify_admin_or_facilitator(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        deals_ref = db.reference('deals', app=db_app).order_by_child('status').equal_to('accepted_by_farmer')
        return jsonify(deals_ref.get() or {}), 200
    except Exception as e: return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/admin/deals/action/<deal_id>', methods=['POST'])
def admin_action_on_deal(deal_id):
    auth_header = request.headers.get('Authorization')
    reviewer_uid = None
    try:
        reviewer_uid, _, _ = verify_admin_or_facilitator(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        data = request.get_json(); action = data.get('action')
        if action not in ['approve', 'reject']: return jsonify({'error': 'Invalid action.'}), 400
        deal_ref = db.reference(f'deals/{deal_id}', app=db_app); deal_data = deal_ref.get()
        if not deal_data or deal_data.get('status') != 'accepted_by_farmer': return jsonify({'error': 'Deal not found or not in correct state for admin action'}), 404
        update_time = datetime.now(timezone.utc).isoformat()
        farmer_id, buyer_id = deal_data.get('farmer_id'), deal_data.get('buyer_id')
        message_text = "" # Renamed
        if action == 'approve':
            deal_ref.update({'status': 'active', 'admin_approved_by': reviewer_uid, 'admin_approved_at': update_time})
            message_text = f"Your deal (ID: {deal_id}) has been approved by admin and is now active."
        elif action == 'reject':
            deal_ref.update({'status': 'rejected_by_admin', 'admin_rejected_by': reviewer_uid, 'admin_rejected_at': update_time})
            message_text = f"Your deal (ID: {deal_id}) has been rejected by admin."
        if message_text:
            _send_system_notification(farmer_id, message_text, "deal_status_update", f"/deals/{deal_id}")
            _send_system_notification(buyer_id, message_text, "deal_status_update", f"/deals/{deal_id}")
        return jsonify({'success': True, 'message': message_text or "Action processed."}), 200
    except Exception as e: return handle_route_errors(e, uid_context=reviewer_uid)

@app.route('/api/chat/send', methods=['POST'])
def send_chat_message():
    auth_header = request.headers.get('Authorization');
    uid = None
    try:
        uid = verify_token(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error'}), 503
        data = request.get_json(); chat_room_id, msg_text = data.get('chat_room_id'), data.get('message_text')
        if not chat_room_id or not msg_text: return jsonify({'error': 'chat_room_id and message_text required'}), 400
        message_id = str(uuid.uuid4())
        message_data = {'sender_id': uid, 'text': msg_text, 'timestamp': datetime.now(timezone.utc).isoformat()}
        db.reference(f'chat_messages/{chat_room_id}/{message_id}', app=db_app).set(message_data)
        return jsonify({'success': True, 'message_id': message_id}), 201
    except Exception as e: return handle_route_errors(e, uid_context=uid)

@app.route('/api/chat/<chat_room_id>', methods=['GET'])
def get_chat_messages(chat_room_id):
    auth_header = request.headers.get('Authorization');
    uid = None
    try:
        uid = verify_token(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error'}), 503
        messages_ref = db.reference(f'chat_messages/{chat_room_id}', app=db_app).order_by_child('timestamp')
        return jsonify(messages_ref.get() or {}), 200
    except Exception as e: return handle_route_errors(e, uid_context=uid)

@app.route('/api/admin/notifications/send', methods=['POST'])
def admin_send_notification():
    auth_header = request.headers.get('Authorization')
    admin_uid = None
    try:
        admin_uid = verify_admin(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        
        data = request.get_json()
        message_content = data.get('message') # For the in-app notification
        target_group = data.get('target_group', 'all')
        target_users_list = data.get('target_users', [])
        
        # New email-specific fields from frontend
        send_as_email = data.get('send_as_email', False)
        email_subject = data.get('email_subject')
        email_body_html = data.get('email_body_html')

        if not message_content:
            return jsonify({'error': 'In-app notification message is required'}), 400
        if send_as_email and (not email_subject or not email_body_html):
            return jsonify({'error': 'If sending as email, email_subject and email_body_html are required.'}), 400

        recipients_uids = set()
        all_users_data = db.reference('users', app=db_app).get() or {}
        
        if target_users_list and isinstance(target_users_list, list):
            for uid_target in target_users_list:
                if uid_target in all_users_data: recipients_uids.add(uid_target)
        elif target_group == 'all':
            recipients_uids.update(all_users_data.keys())
        elif target_group in ['farmers', 'buyers', 'transporters']:
            role_key = target_group[:-1] # 'farmers' -> 'farmer'
            for uid_loop, u_data in all_users_data.items():
                if u_data and u_data.get('roles', {}).get(role_key, False):
                    recipients_uids.add(uid_loop)
        else:
            return jsonify({'error': 'Invalid target_group or target_users not provided correctly'}), 400
        
        sent_count = 0
        for uid_recipient in recipients_uids:
            # Call the upgraded notification function with all parameters
            if _send_system_notification(
                user_id=uid_recipient,
                message_content=message_content,
                notif_type="admin_broadcast",
                send_email=send_as_email,
                email_subject=email_subject,
                email_body=email_body_html
            ):
                sent_count += 1
                
        return jsonify({'success': True, 'message': f"Broadcast notification dispatched for {sent_count} user(s)."}), 200
        
    except Exception as e:
        return handle_route_errors(e, uid_context=admin_uid)

@app.route('/api/user/notifications', methods=['GET'])
def get_user_notifications():
    auth_header = request.headers.get('Authorization');
    uid = None
    try:
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error'}), 503
        uid = verify_token(auth_header)
        if not uid: return jsonify({'error': 'Authentication required.'}), 401
        notifications_ref = db.reference(f'notifications/{uid}', app=db_app).order_by_child('created_at')
        user_notifications = notifications_ref.get() or {}
        sorted_notifications = sorted(user_notifications.items(), key=lambda item: item[1]['created_at'], reverse=True)
        return jsonify(dict(sorted_notifications)), 200
    except Exception as e: return handle_route_errors(e, uid_context=uid)

@app.route('/api/user/notifications/<notification_id>/read', methods=['POST'])
def mark_notification_read(notification_id):
    auth_header = request.headers.get('Authorization');
    uid = None
    try:
        uid = verify_token(auth_header)
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error'}), 503
        notif_ref = db.reference(f'notifications/{uid}/{notification_id}', app=db_app)
        if not notif_ref.get(): return jsonify({'error': 'Notification not found'}), 404
        notif_ref.update({'read': True, 'read_at': datetime.now(timezone.utc).isoformat()})
        return jsonify({'success': True, 'message': 'Notification marked as read.'}), 200
    except Exception as e: return handle_route_errors(e, uid_context=uid)

# Helper for AI chat to fetch platform data
def _fetch_platform_data_for_chat(query):
    if not FIREBASE_INITIALIZED: return "Firebase not ready.", False

    listings_ref = db.reference('listings', app=db_app).order_by_child('status').equal_to('active')
    all_active_listings = listings_ref.get() or {}

    relevant_listings = []
    query_lower = query.lower()

    for lid, ldata in all_active_listings.items():
        if not ldata: continue
        crop_type = ldata.get('crop_type', '').lower()
        location = ldata.get('location', '').lower()
        listing_type = ldata.get('listing_type', '')

        # Simple keyword matching for demonstration
        if any(keyword in query_lower for keyword in [crop_type, location, listing_type, 'maize', 'beans', 'harare', 'bulawayo']):
            relevant_listings.append(ldata)

    if not relevant_listings:
        return "No active listings found matching your query.", False

    summary = "Active Listings:\n"
    for l in relevant_listings[:5]: # Limit to top 5 for brevity
        summary += f"- {l.get('crop_type')} ({l.get('listing_type')}) in {l.get('location')}, Qty: {l.get('quantity')}, Price: {l.get('asking_price') or l.get('price_range')}\n"

    return summary, True

# Helper for AI chat to fetch price trends
def _get_price_trend_analysis_for_chat(crop_type=None, location=None):
    if not FIREBASE_INITIALIZED: return "Firebase not ready.", False
    if not gemini_client: return "AI service not available for trend analysis.", False

    all_deals = db.reference('deals', app=db_app).order_by_child('status').equal_to('completed').get() or {}
    price_data_points = []
    for deal_id, deal in all_deals.items():
        if not deal: continue
        listing_id = deal.get('listing_id')
        listing_details = db.reference(f'listings/{listing_id}', app=db_app).get() if listing_id else None
        if listing_details:
            deal_crop_type, deal_location = listing_details.get('crop_type'), listing_details.get('location')
            if crop_type and deal_crop_type and deal_crop_type.lower() != crop_type.lower(): continue
            if location and deal_location and deal_location.lower() != location.lower(): continue
            price_data_points.append({
                'price': deal.get('agreed_price') or deal.get('proposed_price'),
                'quantity': deal.get('agreed_quantity') or deal.get('proposed_quantity'),
                'date': deal.get('admin_approved_at') or deal.get('created_at'),
                'crop': deal_crop_type, 'location': deal_location
            })

    if not price_data_points:
        return "Not enough historical data to generate price trends for the specified criteria.", False

    data_summary_for_gemini = f"Recent transactions for {crop_type or 'various crops'} in {location or 'various locations'}:\n"
    for point in price_data_points[:10]: # Limit data sent to Gemini
        data_summary_for_gemini += f"- Crop: {point.get('crop')}, Price: {point.get('price')}, Qty: {point.get('quantity')}, Date: {point.get('date')}, Loc: {point.get('location')}\n"

    prompt = f"""
    Analyze agricultural transaction data for Tunasonga Agri. Provide brief price trend analysis (increasing, decreasing, stable? patterns?).
    Focus on {crop_type if crop_type else 'common crops'}. Be concise for farmers/buyers. State if data is sparse.
    Data: {data_summary_for_gemini}
    Analysis:
    """
    try:
        response_obj = gemini_client.models.generate_content(model='gemini-2.0-flash', contents=[{'parts': [{'text': prompt}]}])
        return response_obj.text.strip(), True
    except Exception as e:
        logger.error(f"Gemini error during price trend analysis: {e}")
        return "Could not generate price trend analysis at this time due to an AI service error.", False


@app.route('/api/market/prices/trends', methods=['GET'])
def get_price_trends():
    uid_context = "public_price_trends"
    response_obj = None
    try:
        if not gemini_client: return jsonify({'error': 'AI service not available.'}), 503
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error: Firebase not ready.'}), 503
        crop_type, location = request.args.get('crop_type'), request.args.get('location')

        trend_analysis, success = _get_price_trend_analysis_for_chat(crop_type, location)

        if not success:
            return jsonify({'message': trend_analysis}), 200 # trend_analysis contains the error message

        return jsonify({'crop_type': crop_type, 'location': location, 'trend_analysis': trend_analysis}), 200
    except AttributeError as ae:
        logger.error(f"Gemini Response Attribute Error in get_price_trends: {ae}. Response object: {response_obj}")
        try: trend_analysis = response_obj.candidates[0].content.parts[0].text if response_obj and response_obj.candidates else "Error processing AI structure."
        except Exception: trend_analysis = "Error processing AI response structure."
        return jsonify({'crop_type': crop_type, 'location': location, 'trend_analysis': trend_analysis, 'error_detail': str(ae)}), 200
    except Exception as e: return handle_route_errors(e, uid_context=uid_context)

@app.route("/api/ai/chat", methods=["POST"])
def ai_chat():
    auth_header = request.headers.get("Authorization", "")
    uid = None
    intent = "general_agri_info"  # start with a valid default rather than "unknown"
    try:
        if not FIREBASE_INITIALIZED or not gemini_client:
            return jsonify({'error': 'Server or AI service not ready.'}), 503
        
        uid = verify_token(auth_header)

        data = request.get_json()
        if not data:
            return jsonify({"error": "Invalid request data."}), 400

        user_message = data.get("message", "").strip()
        if not user_message:
            return jsonify({"error": "Message cannot be empty."}), 400

        # 1) Build a more constrained classification prompt
        classify_prompt = f"""
Classify the user’s query into exactly one of these categories (and nothing else):
platform_data_query
price_trend_query
general_agri_info
other

User Query: "{user_message}"

Return exactly one of the four category names above, with no extra words or punctuation.
"""
        # 2) Call Gemini for classification, with explicit logging
        try:
            response_obj_gemini = gemini_client.models.generate_content(
                model='gemini-2.0-flash',
                contents=[{'parts': [{'text': classify_prompt}]}]
            )
            raw_intent = response_obj_gemini.text or ""
        except Exception as classify_ex:
            logger.error(f"Classification call failed: {classify_ex}")
            raw_intent = ""
        # 3) Normalize and validate
        normalized = raw_intent.strip().replace('"', '').lower()
        valid_intents = ["platform_data_query", "price_trend_query", "general_agri_info", "other"]
        if normalized in valid_intents:
            intent = normalized
        else:
            logger.warning(f"Unexpected or empty classification '{raw_intent}'. Defaulting intent to general_agri_info.")
            intent = "general_agri_info"

        # 4) Build context based on intent...
        context_for_gemini = ""
        if intent == "platform_data_query":
            platform_data_summary, _ = _fetch_platform_data_for_chat(user_message)
            if platform_data_summary:
                context_for_gemini += f"Current Platform Data Context:\n{platform_data_summary}\n\n"
        elif intent == "price_trend_query":
            # … trend logic …
            trend_analysis_summary, _ = _get_price_trend_analysis_for_chat(...)
            if trend_analysis_summary:
                context_for_gemini += f"Price Trend Analysis Context:\n{trend_analysis_summary}\n\n"

        # 5) Main answer prompt
        main_prompt = f"""
You are Tunasonga Agri Assistant, an AI for an agricultural marketplace in Zimbabwe and SADC.
Your goal is to provide helpful, concise, and accurate information. Your persona is professional, friendly, and supportive of farmers and agri-businesses.
The user's original query intent was classified as: {intent}
{context_for_gemini}
Based on the user's query and any provided context above, please formulate your answer to the user.
User Query: "{user_message}"
Specific Instructions based on intent:
- If the intent was 'platform_data_query': Use the "Current Platform Data Context" to answer. If the context says no items were found, relay that and suggest they browse the marketplace or refine their search. Do not invent listings.
- If the intent was 'price_trend_query': Use the "Price Trend Analysis Context". If the context says trends couldn't be generated, relay that. Do not invent trends.
- For 'general_agri_info': Use your broad agricultural knowledge. Focus on practices relevant to the SADC region, smallholder farmers, climate-smart agriculture, market access, and agri-business development. Provide actionable advice if possible.
- If the query is unclear, classified as "other", or if the context is insufficient for a specific query: Provide a polite general response, ask for clarification, or gently guide the user on how you can help (e.g., "I can help with finding produce, getting price trends, or general farming advice. What would you like to know?").
Keep your answers clear and easy to understand. Avoid overly technical jargon unless necessary and explain it.
Answer:
"""
        
        try:
            response_obj_gemini = gemini_client.models.generate_content(
                model='gemini-2.0-flash',
                contents=[{'parts': [{'text': main_prompt}]}]
            )
            ai_response_text = response_obj_gemini.text.strip() or "I’m having trouble generating a response right now."
        except Exception as answer_ex:
            logger.error(f"Answer generation failed: {answer_ex}")
            ai_response_text = "I’m having trouble generating a response right now."

        # 6) Save to Firebase history
        try:
            db.reference(f'ai_chat_history/{uid}/{str(uuid.uuid4())}', app=db_app).set({
                'user_message': user_message,
                'ai_response': ai_response_text,
                'intent_classified': intent,
                'timestamp': datetime.now(timezone.utc).isoformat()
            })
        except Exception as chat_history_error:
            logger.error(f"Failed to store chat history for UID {uid}: {chat_history_error}")

        # 7) Return JSON with valid intent
        return jsonify({"response": ai_response_text, "intent": intent})

    except AttributeError as ae:
        # In this branch, always return a valid default intent
        logger.error(f"AttributeError in ai_chat (UID: {uid}): {ae}")
        ai_response_text = "I’m having a little trouble understanding that. Could you try rephrasing?"
        return jsonify({"response": ai_response_text, "intent": "general_agri_info", "error_detail": "AI_RESPONSE_FORMAT_ISSUE"}), 200
    except Exception as e:
        # For any other exception, ensure we return a valid intent instead of "unknown"
        logger.error(f"Unhandled exception in ai_chat (UID: {uid}): {e}")
        return jsonify({"error": str(e), "intent": "general_agri_info"}), 500

@app.route('/api/user/ai-chat-history', methods=['GET'])
def get_ai_chat_history():
    auth_header = request.headers.get('Authorization');
    uid = None
    try:
        if not FIREBASE_INITIALIZED: return jsonify({'error': 'Server configuration error'}), 503
        uid = verify_token(auth_header)
        if not uid: return jsonify({'error': 'Authentication required.'}), 401
        history_ref = db.reference(f'ai_chat_history/{uid}', app=db_app).order_by_child('timestamp')
        chat_history = history_ref.get() or {}
        sorted_history = sorted(chat_history.items(), key=lambda item: item[1]['timestamp'], reverse=True)
        return jsonify(dict(sorted_history)), 200
    except Exception as e: return handle_route_errors(e, uid_context=uid)

        
@app.route('/api/deals/<deal_id>/payment/initiate', methods=['POST'])
def initiate_payment(deal_id):
    auth_header = request.headers.get('Authorization')
    buyer_uid = None
    try:
        if not paynow_client:
            return jsonify({'error': 'Payment service is not configured.'}), 503
        
        buyer_uid = verify_token(auth_header)
        
        deal_ref = db.reference(f'deals/{deal_id}', app=db_app)
        deal_data = deal_ref.get()

        # --- SURGICAL VALIDATION ---
        if not deal_data:
            return jsonify({'error': 'Deal not found.'}), 404
        if deal_data.get('buyer_id') != buyer_uid:
            return jsonify({'error': 'You are not authorized to pay for this deal.'}), 403
        if deal_data.get('status') != 'active':
            return jsonify({'error': 'This deal is not active and cannot be paid for.'}), 400
        if deal_data.get('payment', {}).get('status') == 'paid':
            return jsonify({'error': 'This deal has already been paid for.'}), 400

        # --- BACKEND CALCULATION ---
        price = float(deal_data['proposed_price'])
        quantity = int(deal_data['proposed_quantity'])
        total_amount = round(price * quantity, 2)

        # Create a new payment object
        payment = paynow_client.create_payment(
            f"TNSG-{deal_id}",  # A unique reference for this transaction
            deal_data.get('buyer_email', 'buyer@example.com') # Get buyer email if stored, otherwise a placeholder
        )
        payment.add(f"Deal {deal_id} for {deal_data.get('crop_type', 'produce')}", total_amount)

        # Send the payment to Paynow
        response = paynow_client.send(payment)

        if not response.success:
            logger.error(f"Paynow initiation failed for deal {deal_id}: {response.error}")
            return jsonify({'error': 'Failed to initiate payment with the provider.', 'details': response.error}), 500

        # --- UPDATE FIREBASE BEFORE REDIRECT ---
        payment_update_payload = {
            "status": "pending",
            "paynow_reference": response.paynow_reference,
            "poll_url": response.poll_url,
            "amount": total_amount,
            "currency": "USD", # Or make this dynamic if needed
            "initiated_at": datetime.now(timezone.utc).isoformat()
        }
        deal_ref.child('payment').set(payment_update_payload)

        # Return the redirect URL to the frontend
        return jsonify({
            'success': True, 
            'message': 'Payment initiated. Redirecting...',
            'redirect_url': response.redirect_url
        }), 200

    except Exception as e:
        return handle_route_errors(e, uid_context=buyer_uid)

@app.route('/api/payment/webhook/paynow', methods=['POST'])
def paynow_webhook():
    try:
        # The Paynow SDK does not have a built-in webhook handler, so we do it manually.
        # This is a simplified representation. Refer to Paynow docs for the exact fields and hash method.
        paynow_data = request.form.to_dict() # Paynow sends form data
        logger.info(f"Received Paynow webhook: {paynow_data}")

        paynow_reference = paynow_data.get('paynowreference')
        merchant_reference = paynow_data.get('reference') # This is our "TNSG-deal_id"
        status = paynow_data.get('status', '').lower()
        received_hash = paynow_data.get('hash')

        # --- CRITICAL: HASH VERIFICATION ---
        # You MUST generate a hash from the received data using your Integration Key
        # and compare it to the received_hash. If they don't match, discard the request.
        # Example (pseudo-code, check Paynow docs for exact implementation):
        # calculated_hash = generate_hash(paynow_data, PAYNOW_INTEGRATION_KEY)
        # if calculated_hash != received_hash:
        #     logger.warning("Invalid hash on Paynow webhook. Discarding.")
        #     return jsonify({'error': 'Invalid hash'}), 403

        if not merchant_reference or not merchant_reference.startswith('TNSG-'):
            return jsonify({'error': 'Invalid reference format'}), 400

        deal_id = merchant_reference.split('TNSG-')[1]
        deal_ref = db.reference(f'deals/{deal_id}', app=db_app)
        deal_data = deal_ref.get()

        if not deal_data:
            logger.error(f"Webhook for non-existent deal {deal_id} received.")
            return jsonify({'error': 'Deal not found'}), 404
        
        # Prevent processing old webhooks if deal is already paid
        if deal_data.get('payment', {}).get('status') == 'paid':
             logger.info(f"Webhook for already paid deal {deal_id} received. Ignoring.")
             return jsonify({'status': 'ok'}), 200

        payment_update_payload = {
            "status": status,
            "completed_at": datetime.now(timezone.utc).isoformat()
        }
        deal_ref.child('payment').update(payment_update_payload)
        
        # --- NOTIFY USERS BASED ON STATUS ---
        if status == 'paid':
            farmer_id = deal_data.get('farmer_id')
            buyer_id = deal_data.get('buyer_id')
            
            # Find admins to notify
            admins_ref = db.reference('users', app=db_app).order_by_child('is_admin').equal_to(True).get()

            success_message = f"Payment for deal {deal_id} has been successfully received."
            
            _send_system_notification(buyer_id, f"Your payment for deal {deal_id} was successful.", "payment_success", f"/deals/{deal_id}")
            _send_system_notification(farmer_id, success_message, "payment_received", f"/deals/{deal_id}")
            if admins_ref:
                for admin_id, _ in admins_ref.items():
                    _send_system_notification(admin_id, success_message, "admin_payment_notification", f"/admin/deals/{deal_id}")

        # Acknowledge receipt to Paynow
        return jsonify({'status': 'ok'}), 200

    except Exception as e:
        logger.error(f"Error in Paynow webhook: {e}\n{traceback.format_exc()}")
        return jsonify({'error': 'Internal server error'}), 500


if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0", port=int(os.getenv("PORT", 7860)))