import 'package:flutter_bloc/flutter_bloc.dart'; import '../../data/models/teacher_models.dart'; import '../../data/repositories/teacher_repository.dart'; /** * ============================================================================== * SAQEL TEACHER STUDIO - MONETIZATION CUBIT * ============================================================================== * * إدارة المحفظة المالية والتسييل وسحوبات كليك (CliQ Payouts): * - حساب عوائد النموذج المزدوج (1,420 مجاني مدعوم مقابل 380 مدفوع خارجي) * - تقسيم الحصص: 55% للمعلم / 15% لمديرية الثقافة / 30% للمنصة * - إرسال واعتماد طلبات السحب عبر كليك. */ class TeacherMonetizationState { final double institutionalStudents; final double studentSubscribers; final double pricePerCourse; final double grossRevenue; final double teacherShare; final double directorateShare; final double platformShare; final double availableBalance; final double totalWithdrawn; final String cliqAlias; final List courses; final List payoutRequests; final bool isSubmittingPayout; final bool isLoading; const TeacherMonetizationState({ required this.institutionalStudents, required this.studentSubscribers, required this.pricePerCourse, required this.grossRevenue, required this.teacherShare, required this.directorateShare, required this.platformShare, required this.availableBalance, required this.totalWithdrawn, required this.cliqAlias, required this.courses, required this.payoutRequests, required this.isSubmittingPayout, this.isLoading = false, }); TeacherMonetizationState copyWith({ double? institutionalStudents, double? studentSubscribers, double? pricePerCourse, double? grossRevenue, double? teacherShare, double? directorateShare, double? platformShare, double? availableBalance, double? totalWithdrawn, String? cliqAlias, List? courses, List? payoutRequests, bool? isSubmittingPayout, bool? isLoading, }) { return TeacherMonetizationState( institutionalStudents: institutionalStudents ?? this.institutionalStudents, studentSubscribers: studentSubscribers ?? this.studentSubscribers, pricePerCourse: pricePerCourse ?? this.pricePerCourse, grossRevenue: grossRevenue ?? this.grossRevenue, teacherShare: teacherShare ?? this.teacherShare, directorateShare: directorateShare ?? this.directorateShare, platformShare: platformShare ?? this.platformShare, availableBalance: availableBalance ?? this.availableBalance, totalWithdrawn: totalWithdrawn ?? this.totalWithdrawn, cliqAlias: cliqAlias ?? this.cliqAlias, courses: courses ?? this.courses, payoutRequests: payoutRequests ?? this.payoutRequests, isSubmittingPayout: isSubmittingPayout ?? this.isSubmittingPayout, isLoading: isLoading ?? this.isLoading, ); } } class TeacherMonetizationCubit extends Cubit { final TeacherRepository repository; TeacherMonetizationCubit({required this.repository}) : super(const TeacherMonetizationState( institutionalStudents: 83, studentSubscribers: 0, pricePerCourse: 20.0, grossRevenue: 0.0, teacherShare: 0.0, directorateShare: 0.0, platformShare: 0.0, availableBalance: 0.0, totalWithdrawn: 0.0, cliqAlias: '0798583052@CLIQ', courses: [], payoutRequests: [], isSubmittingPayout: false, isLoading: false, )); Future loadMonetization() async { emit(state.copyWith(isLoading: true)); try { final data = await repository.getMonetizationDashboard(); final courses = await repository.getPublishedCourses(); final audience = data['audience_breakdown'] as Map? ?? {}; final inst = audience['institutional_students'] as Map? ?? {}; final mkt = audience['marketplace_students'] as Map? ?? {}; final wallet = data['wallet'] as Map? ?? {}; final instCount = (inst['count'] as num?)?.toDouble() ?? 83.0; final paidCount = (mkt['count'] as num?)?.toDouble() ?? 0.0; final gross = (data['gross_revenue_jod'] as num?)?.toDouble() ?? (paidCount * 20.0); final tShare = gross * 0.55; final dShare = gross * 0.15; final pShare = gross * 0.30; final avail = (wallet['available_balance_jod'] as num?)?.toDouble() ?? tShare; final withdrawn = (wallet['total_withdrawn_jod'] as num?)?.toDouble() ?? 0.0; final alias = wallet['cliq_payout_alias']?.toString() ?? '0798583052@CLIQ'; List payouts = []; if (wallet['recent_payouts'] is List) { payouts = (wallet['recent_payouts'] as List).map((p) { return TeacherPayoutRequestModel( cliqAlias: p['teacher_cliq_alias']?.toString() ?? alias, amountJod: (p['amount_jod'] as num?)?.toDouble() ?? 0.0, requestedAt: p['created_at']?.toString() ?? 'اليوم', status: p['status']?.toString() ?? 'queued', ); }).toList(); } emit(state.copyWith( institutionalStudents: instCount, studentSubscribers: paidCount, grossRevenue: gross, teacherShare: tShare, directorateShare: dShare, platformShare: pShare, availableBalance: avail, totalWithdrawn: withdrawn, cliqAlias: alias, courses: courses, payoutRequests: payouts, isLoading: false, )); } catch (_) { emit(state.copyWith(isLoading: false)); } } void updateSubscribers(double subscribers) { final gross = subscribers * state.pricePerCourse; emit(state.copyWith( studentSubscribers: subscribers, grossRevenue: gross, teacherShare: gross * 0.55, directorateShare: gross * 0.15, platformShare: gross * 0.30, availableBalance: gross * 0.55, )); } Future submitCliqPayout({ required String cliqAlias, required double amountJod, }) async { emit(state.copyWith(isSubmittingPayout: true)); try { final req = await repository.requestCliqPayout( cliqAlias: cliqAlias, amountJod: amountJod, ); final updatedList = List.from(state.payoutRequests)..insert(0, req); final newAvail = (state.availableBalance - amountJod).clamp(0.0, double.infinity); final newWithdrawn = state.totalWithdrawn + amountJod; emit(state.copyWith( payoutRequests: updatedList, availableBalance: newAvail, totalWithdrawn: newWithdrawn, isSubmittingPayout: false, )); } catch (_) { emit(state.copyWith(isSubmittingPayout: false)); } } }