import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../providers/tariff_provider.dart'; import '../../theme/app_theme.dart'; import '../../theme/etm_theme.dart'; import '../../widgets/pro_lock_badge.dart'; /// Écran "Tarifs & providers". class TariffScreen extends StatefulWidget { const TariffScreen({super.key}); @override State createState() => _TariffScreenState(); } class _TariffScreenState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().load(); }); } @override Widget build(BuildContext context) { final tariff = context.watch(); return Scaffold( backgroundColor: const Color(0xFFF0F2F5), appBar: AppBar( title: const Text('Tarifs & providers'), backgroundColor: Colors.white, foregroundColor: const Color(0xFF1A1A2E), elevation: 0, ), body: tariff.loading ? const Center(child: CircularProgressIndicator()) : ListView( padding: const EdgeInsets.all(16), children: [ _ProviderCard(tariff), // Carte tarif manuel uniquement si provider = manual if (tariff.activeProvider == TariffProviderType.manual) ...[ const SizedBox(height: 12), _ManualTariffCard(tariff), ] else ...[ const SizedBox(height: 12), _ModeCard(tariff), if (tariff.mode == TariffMode.hchp) ...[ const SizedBox(height: 12), _HcHpCard(tariff), ], const SizedBox(height: 12), _PricesCard(tariff), ], ], ), ); } } // ── Carte provider ──────────────────────────────────────────────────────────── class _ProviderCard extends StatelessWidget { final TariffProvider tariff; const _ProviderCard(this.tariff); @override Widget build(BuildContext context) { return _SectionCard( title: 'Provider actif', child: Column( children: TariffProviderType.values.map((p) { final selected = tariff.activeProvider == p; return _ProviderTile( provider: p, selected: selected, onTap: p.isPro ? null : () => context.read().setProvider(p), ); }).toList(), ), ); } } class _ProviderTile extends StatelessWidget { final TariffProviderType provider; final bool selected; final VoidCallback? onTap; const _ProviderTile({ required this.provider, required this.selected, this.onTap, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Opacity( opacity: provider.isPro ? 0.6 : 1.0, child: Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ Icon( selected ? Icons.check_circle_rounded : Icons.radio_button_unchecked_rounded, color: selected ? AppTheme.primaryGreen : Colors.grey, size: 20, ), const SizedBox(width: 12), Expanded( child: Text(provider.label, style: const TextStyle(fontSize: 13)), ), if (provider.isPro) ProLockBadge(featureName: provider.label), ], ), ), ), ); } } // ── Carte mode tarifaire ────────────────────────────────────────────────────── class _ModeCard extends StatelessWidget { final TariffProvider tariff; const _ModeCard(this.tariff); @override Widget build(BuildContext context) { return _SectionCard( title: 'Mode tarifaire', child: DropdownButtonFormField( value: tariff.mode, decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(12)), contentPadding: const EdgeInsets.symmetric( horizontal: 14, vertical: 12), ), items: TariffMode.values .map((m) => DropdownMenuItem(value: m, child: Text(m.label))) .toList(), onChanged: (v) { if (v != null) context.read().setMode(v); }, ), ); } } // ── Carte HC/HP ─────────────────────────────────────────────────────────────── class _HcHpCard extends StatelessWidget { final TariffProvider tariff; const _HcHpCard(this.tariff); @override Widget build(BuildContext context) { final hchp = tariff.hchp; return _SectionCard( title: 'Tarif HC/HP', child: Column( children: [ _PriceRow( label: 'Prix HC', value: hchp.offPeakPrice, unit: '€/kWh', onChanged: (v) => context .read() .updateHcHp(hchp.copyWith(offPeakPrice: v)), ), _PriceRow( label: 'Prix HP', value: hchp.peakPrice, unit: '€/kWh', onChanged: (v) => context .read() .updateHcHp(hchp.copyWith(peakPrice: v)), ), _TimeRow( label: 'Début HC', time: hchp.offPeakStart, onChanged: (t) => context .read() .updateHcHp(hchp.copyWith(offPeakStart: t)), ), _TimeRow( label: 'Fin HC', time: hchp.offPeakEnd, onChanged: (t) => context .read() .updateHcHp(hchp.copyWith(offPeakEnd: t)), ), ], ), ); } } class _PriceRow extends StatefulWidget { final String label; final double value; final String unit; final ValueChanged onChanged; const _PriceRow({ required this.label, required this.value, required this.unit, required this.onChanged, }); @override State<_PriceRow> createState() => _PriceRowState(); } class _PriceRowState extends State<_PriceRow> { late TextEditingController _ctrl; @override void initState() { super.initState(); _ctrl = TextEditingController( text: widget.value.toStringAsFixed(3)); } @override void dispose() { _ctrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( children: [ Expanded( child: Text(widget.label, style: const TextStyle(fontSize: 13)), ), SizedBox( width: 90, child: TextFormField( controller: _ctrl, textAlign: TextAlign.center, keyboardType: const TextInputType.numberWithOptions( decimal: true), decoration: InputDecoration( isDense: true, filled: true, fillColor: Colors.grey.shade50, border: OutlineInputBorder( borderRadius: BorderRadius.circular(8)), contentPadding: const EdgeInsets.symmetric( horizontal: 8, vertical: 8), ), onFieldSubmitted: (v) { final n = double.tryParse(v); if (n != null) widget.onChanged(n); }, ), ), const SizedBox(width: 6), Text(widget.unit, style: const TextStyle( fontSize: 12, color: AppTheme.textLight)), ], ), ); } } class _TimeRow extends StatelessWidget { final String label; final TimeOfDay time; final ValueChanged onChanged; const _TimeRow({ required this.label, required this.time, required this.onChanged, }); @override Widget build(BuildContext context) { final formatted = '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}'; return Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( children: [ Expanded( child: Text(label, style: const TextStyle(fontSize: 13))), GestureDetector( onTap: () async { final picked = await showTimePicker( context: context, initialTime: time, ); if (picked != null) onChanged(picked); }, child: Container( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8), decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(8), color: Colors.grey.shade50, ), child: Text(formatted, style: const TextStyle( fontSize: 13, fontWeight: FontWeight.w500)), ), ), ], ), ); } } // ── Carte tarif manuel ──────────────────────────────────────────────────────── class _ManualTariffCard extends StatefulWidget { final TariffProvider tariff; const _ManualTariffCard(this.tariff); @override State<_ManualTariffCard> createState() => _ManualTariffCardState(); } class _ManualTariffCardState extends State<_ManualTariffCard> { late TextEditingController _ctrl; @override void initState() { super.initState(); _ctrl = TextEditingController( text: widget.tariff.manualPrice.toStringAsFixed(4)); } @override void dispose() { _ctrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return _SectionCard( title: 'Tarif manuel', child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Prix unique appliqué à toutes les décisions du scheduler.', style: TextStyle(fontSize: 12, color: AppTheme.textLight), ), const SizedBox(height: 16), Row( children: [ const Expanded( child: Text('Prix de l\'électricité', style: TextStyle(fontSize: 13))), SizedBox( width: 100, child: TextFormField( controller: _ctrl, textAlign: TextAlign.center, keyboardType: const TextInputType.numberWithOptions( decimal: true), decoration: InputDecoration( isDense: true, filled: true, fillColor: Colors.grey.shade50, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10)), contentPadding: const EdgeInsets.symmetric( horizontal: 8, vertical: 10), ), onFieldSubmitted: (v) { final n = double.tryParse(v); if (n != null) { context.read().setManualPrice(n); } }, ), ), const SizedBox(width: 8), const Text('€/kWh', style: TextStyle(fontSize: 12, color: AppTheme.textLight)), ], ), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: ETMTheme.accentColor.withValues(alpha: 0.07), borderRadius: BorderRadius.circular(10), ), child: Row( children: [ const Icon(Icons.info_outline_rounded, size: 15, color: ETMTheme.accentColor), const SizedBox(width: 8), Expanded( child: Text( 'Prix actuel : ${widget.tariff.manualPrice.toStringAsFixed(4)} €/kWh', style: const TextStyle( fontSize: 12, color: ETMTheme.accentColor), ), ), ], ), ), ], ), ); } } // ── Carte prix actuels ──────────────────────────────────────────────────────── class _PricesCard extends StatelessWidget { final TariffProvider tariff; const _PricesCard(this.tariff); @override Widget build(BuildContext context) { final p = tariff.prices; String _fmtTime(DateTime? dt) { if (dt == null) return ''; return ' (${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')})'; } return _SectionCard( title: 'Prix actuels (live)', child: Column( children: [ _PriceItem( label: 'Maintenant', value: '${p.now.toStringAsFixed(3)} €/kWh', ), _PriceItem( label: 'Dans 1h', value: '${p.inOneHour.toStringAsFixed(3)} €/kWh', ), _PriceItem( label: 'Minimum 24h', value: '${p.min24h.toStringAsFixed(3)} €/kWh${_fmtTime(p.minTime)}', color: AppTheme.primaryGreen, ), _PriceItem( label: 'Maximum 24h', value: '${p.max24h.toStringAsFixed(3)} €/kWh${_fmtTime(p.maxTime)}', color: AppTheme.boostRed, ), ], ), ); } } class _PriceItem extends StatelessWidget { final String label; final String value; final Color? color; const _PriceItem({ required this.label, required this.value, this.color, }); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: Row( children: [ Expanded( child: Text(label, style: const TextStyle(fontSize: 13))), Text( value, style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: color ?? AppTheme.textDark, ), ), ], ), ); } } // ── Card générique ──────────────────────────────────────────────────────────── class _SectionCard extends StatelessWidget { final String title; final Widget child; const _SectionCard({required this.title, required this.child}); @override Widget build(BuildContext context) { return Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 14)), const SizedBox(height: 14), child, ], ), ), ); } }