import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../app/theme.dart'; import '../../providers/session_provider.dart'; import '../../shared/api_client.dart'; import '../../shared/api_error.dart'; import '../../shared/models/match.dart'; import '../../shared/premium_dialog.dart'; import '../../shared/widgets/primary_cta.dart'; import '../../shared/widgets/screen_insets.dart'; import '../../shared/models/team.dart'; import '../matches/team_providers.dart'; class StepTransmission extends ConsumerStatefulWidget { const StepTransmission({ super.key, required this.match, required this.onBack, required this.onNext, }); final MatchModel match; final VoidCallback onBack; final VoidCallback onNext; @override ConsumerState createState() => _StepTransmissionState(); } class _StepTransmissionState extends ConsumerState { String _platform = 'matchlivetv'; String _privacy = 'unlisted'; bool _creating = false; Future _createSession() async { setState(() => _creating = true); try { final client = ref.read(apiClientProvider); final session = await client.createSession( widget.match.id, platform: _platform, privacyStatus: _privacy, qualityPreset: '720p_30_2.5mbps', targetBitrate: 2500000, targetFps: 30, ); ref.read(sessionProvider.notifier).setSession(session, match: widget.match); widget.onNext(); } on DioException catch (e) { final apiErr = ApiException.fromDio(e); if (mounted) { if (apiErr?.isPremiumRequired == true) { await showPremiumRequiredDialog( context, message: apiErr!.message, billingUrl: apiErr.billingUrl, ); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(apiErr?.message ?? 'Errore nella creazione sessione')), ); } } } catch (_) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Errore nella creazione sessione')), ); } } finally { if (mounted) setState(() => _creating = false); } } void _onYoutubeTap(Team? team) { if (team == null) return; if (team.isYoutubeReady) { setState(() => _platform = 'youtube'); return; } if (team.canUseYoutube && team.youtubeMode == 'team') { showPremiumRequiredDialog( context, message: 'Collega il canale YouTube dalla pagina Dettagli squadra sul sito, poi seleziona YouTube qui.', billingUrl: team.staffManageUrl ?? team.billingUrl, ); return; } if (team.canUseYoutube && team.youtubeMode == 'matchlivetv_light') { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'YouTube sul canale Match Live TV non è ancora attivo. Riprova più tardi o usa Match Live TV.', ), ), ); return; } showPremiumRequiredDialog( context, message: 'YouTube Live richiede Premium Light o Full.', billingUrl: team.billingUrl, ); } String _youtubeSubtitle(Team? team) { if (team == null || !team.canUseYoutube) { return 'Premium Light o Full'; } if (team.isYoutubeReady) { final label = team.youtubeChannelTitle; if (team.youtubeUsesPlatformChannel) { return label != null ? 'Canale $label' : 'Canale Match Live TV'; } return label != null ? 'Canale $label' : 'Canale collegato'; } if (team.youtubeMode == 'matchlivetv_light') { return 'Canale Match Live TV (in attivazione)'; } return 'Collega canale sul sito'; } void _onExternalPremiumTap(String platform, Team? team) { showPremiumRequiredDialog( context, message: '$platform è disponibile con Premium (in arrivo).', billingUrl: team?.billingUrl, ); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final teamAsync = ref.watch(teamByIdProvider(widget.match.teamId)); return teamAsync.when( loading: () => const Center(child: CircularProgressIndicator(color: AppTheme.primaryRed)), error: (_, __) => const Center(child: Text('Errore caricamento squadra')), data: (team) { final youtubeSelectable = team != null && team.isYoutubeReady; return SingleChildScrollView( padding: ScreenInsets.contentPadding(context, horizontal: 20, vertical: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (team != null) ...[ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppTheme.surfaceElevated, borderRadius: BorderRadius.circular(10), border: Border.all(color: AppTheme.primaryRed.withValues(alpha: 0.3)), ), child: Text( 'Piano ${team.planName} · Staff ${team.staffLimitLabel}' '${team.concurrentStreamsLimit != null ? ' · Dirette ${team.concurrentStreamsUsed}/${team.concurrentStreamsLimit}' : ''}', style: theme.textTheme.bodySmall, ), ), const SizedBox(height: 12), ], Text('Piattaforma', style: theme.textTheme.titleLarge), const SizedBox(height: 12), _PlatformCard( title: 'Match Live TV', subtitle: 'Diretta sul nostro sito (incluso)', selected: _platform == 'matchlivetv', enabled: true, onTap: () => setState(() => _platform = 'matchlivetv'), ), const SizedBox(height: 8), _PlatformCard( title: 'YouTube Live', subtitle: _youtubeSubtitle(team), selected: _platform == 'youtube', enabled: youtubeSelectable, badge: team?.canUseYoutube == true ? null : 'Premium', onTap: () => _onYoutubeTap(team), ), const SizedBox(height: 8), _PlatformCard( title: 'Facebook Live', subtitle: 'Premium — presto disponibile', selected: false, enabled: false, badge: 'Premium', onTap: () => _onExternalPremiumTap('Facebook Live', team), ), const SizedBox(height: 8), _PlatformCard( title: 'Twitch', subtitle: 'Premium — presto disponibile', selected: false, enabled: false, badge: 'Premium', onTap: () => _onExternalPremiumTap('Twitch', team), ), const SizedBox(height: 24), Text('Privacy', style: theme.textTheme.titleLarge), const SizedBox(height: 12), SegmentedButton( segments: const [ ButtonSegment(value: 'public', label: Text('Pubblico')), ButtonSegment(value: 'unlisted', label: Text('Non in elenco')), ], selected: {_privacy}, onSelectionChanged: (s) => setState(() => _privacy = s.first), ), const SizedBox(height: 24), Text('Qualità', style: theme.textTheme.titleLarge), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppTheme.surfaceElevated, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppTheme.primaryRed.withValues(alpha: 0.4)), ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('720p · 30fps · 2.5 Mbps', style: theme.textTheme.titleMedium), const SizedBox(height: 4), Text( 'Bitrate fisso consigliato per reti instabili', style: theme.textTheme.bodyMedium, ), ], ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: AppTheme.primaryRed.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(6), ), child: Text( 'AUTO', style: theme.textTheme.labelLarge?.copyWith( color: AppTheme.primaryRed, fontSize: 11, ), ), ), ], ), ), const SizedBox(height: 32), Row( children: [ Expanded( child: OutlinedButton( onPressed: _creating ? null : widget.onBack, child: const Text('Indietro'), ), ), const SizedBox(width: 12), Expanded( flex: 2, child: PrimaryCta( label: 'AVANTI >', loading: _creating, onPressed: _createSession, icon: Icons.arrow_forward, ), ), ], ), ], ), ); }, ); } } class _PlatformCard extends StatelessWidget { const _PlatformCard({ required this.title, this.subtitle, required this.selected, required this.enabled, this.badge, this.onTap, }); final String title; final String? subtitle; final bool selected; final bool enabled; final String? badge; final VoidCallback? onTap; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Opacity( opacity: enabled ? 1 : 0.55, child: Material( color: Colors.transparent, child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(10), child: Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: selected ? AppTheme.primaryRed.withValues(alpha: 0.15) : AppTheme.surfaceElevated, borderRadius: BorderRadius.circular(10), border: Border.all( color: selected ? AppTheme.primaryRed : Colors.transparent, ), ), child: Row( children: [ Icon( selected ? Icons.radio_button_checked : Icons.radio_button_off, color: selected ? AppTheme.primaryRed : AppTheme.textSecondary, ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: theme.textTheme.titleMedium), if (subtitle != null) Text(subtitle!, style: theme.textTheme.bodyMedium), ], ), ), if (badge != null) Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: AppTheme.textSecondary.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(6), ), child: Text(badge!, style: theme.textTheme.labelSmall), ), ], ), ), ), ), ); } }