import 'dart:ui' as ui;

import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/features/book_appointments/book_appointments_view_model.dart';
import 'package:hmg_patient_app_new/features/book_appointments/models/resp_models/doctor_schedule_response_model.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:provider/provider.dart';

class DoctorScheduleBottomSheet extends StatefulWidget {
  const DoctorScheduleBottomSheet({super.key});

  @override
  State<DoctorScheduleBottomSheet> createState() => _DoctorScheduleBottomSheetState();
}

class _DoctorScheduleBottomSheetState extends State<DoctorScheduleBottomSheet>
    with SingleTickerProviderStateMixin {
  late PageController _pageController;
  late AnimationController _fadeController;
  late Animation<double> _fadeAnimation;

  double currentPage = 0;
  List<List<Map<String, dynamic>>> weeks = [];
  List<DoctorScheduleResponseModel> doctorScheduleResponse = [];
  List<String> freeSlots = [];

  /// True while weeks are being computed off the build thread
  bool _isInitializing = false;

  late BookAppointmentsViewModel bookAppointmentsViewModel;
  late AppState appState;

  @override
  void initState() {
    super.initState();
    _pageController = PageController();
    _fadeController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 400),
    );
    _fadeAnimation = CurvedAnimation(parent: _fadeController, curve: Curves.easeIn);
  }

  @override
  void dispose() {
    _pageController.dispose();
    _fadeController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: true);
    appState = getIt.get<AppState>();
    final isArabic = appState.isArabic();

    // Trigger initialization after the first frame so the UI never freezes
    final responseReady = bookAppointmentsViewModel.doctorScheduleResponse != null;
    if (responseReady && weeks.isEmpty && !_isInitializing) {
      WidgetsBinding.instance.addPostFrameCallback((_) => _triggerInit());
    }

    // ── API loading ──────────────────────────────────────────────────────────
    if (bookAppointmentsViewModel.isDoctorScheduleLoading || _isInitializing) {
      return Center(
        child: CircularProgressIndicator(
          color: AppColors.primaryRedColor,
          strokeWidth: 2.5,
        ),
      );
    }

    // ── No data ──────────────────────────────────────────────────────────────
    if (weeks.isEmpty) {
      return Center(
        child: Utils.getNoDataWidget(
          context,
          noDataText: LocaleKeys.noScheduleAvailable.tr(context: context),
        ),
      );
    }

    // ── Schedule ready — fade in ─────────────────────────────────────────────
    return FadeTransition(
      opacity: _fadeAnimation,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildHeader(context, isArabic),
          SizedBox(height: 20.h),
          Expanded(
            child: PageView.builder(
              controller: _pageController,
              itemCount: weeks.length,
              onPageChanged: (index) => setState(() => currentPage = index.toDouble()),
              itemBuilder: (context, weekIndex) => _buildWeekView(weekIndex, isArabic),
            ),
          ),
        ],
      ),
    );
  }

  // ── Initialization ─────────────────────────────────────────────────────────

  void _triggerInit() {
    if (!mounted || _isInitializing || weeks.isNotEmpty) return;
    setState(() => _isInitializing = true);

    // Defer heavy work to the next microtask so the spinner is painted first
    Future.microtask(() {
      _buildWeeksFromResponse();
      if (mounted) {
        setState(() => _isInitializing = false);
        _fadeController.forward();
      }
    });
  }

  void _buildWeeksFromResponse() {
    final response = bookAppointmentsViewModel.doctorScheduleResponse;
    if (response == null) return;

    final scheduleList = response['List_DoctorWorkingHoursTable'] as List?;
    if (scheduleList == null || scheduleList.isEmpty) return;

    doctorScheduleResponse =
        scheduleList.map((item) => DoctorScheduleResponseModel.fromJson(item)).toList();

    // Resolve free-slot dates
    if (bookAppointmentsViewModel.doctorFreeSlotDates.isNotEmpty) {
      freeSlots = bookAppointmentsViewModel.doctorFreeSlotDates;
    } else if (bookAppointmentsViewModel.freeSlotsResponse != null &&
        bookAppointmentsViewModel.freeSlotsResponse.isNotEmpty) {
      freeSlots = List<String>.from(bookAppointmentsViewModel.freeSlotsResponse);
    } else if (response['FreeTimeSlots'] != null) {
      freeSlots = List<String>.from(response['FreeTimeSlots']);
    }

    _generateWeeksSchedules();
  }

  /// Splits ALL API days into 7-day chunks — one chunk per page.
  /// Supports full 3-month schedules (~13 weeks) returned by the API.
  void _generateWeeksSchedules() {
    weeks.clear();

    // Convert every API day into a flat map and mark free slots
    final allDays = doctorScheduleResponse.map((workDay) {
      return <String, dynamic>{
        'Date': workDay.date ?? '',
        'DayName': workDay.dayName ?? '',
        'WorkingHours': workDay.workingHours ?? '',
        'fullDay': !_hasFreeSlot(workDay.date ?? ''),
      };
    }).toList();

    // Slice into pages of 7 days each
    const daysPerPage = 7;
    for (var i = 0; i < allDays.length; i += daysPerPage) {
      final end = (i + daysPerPage).clamp(0, allDays.length);
      weeks.add(allDays.sublist(i, end));
    }
  }

  // ── Header ─────────────────────────────────────────────────────────────────

  Widget _buildHeader(BuildContext context, bool isArabic) {
    final currentWeek = weeks[currentPage.round()];
    final firstDate = DateUtil.convertStringToDate(currentWeek.first['Date'] as String);
    final lastDate = DateUtil.convertStringToDate(currentWeek.last['Date'] as String);

    final dateRangeLabel = isArabic
        ? '${firstDate.day} ${DateUtil.getMonthArabic(firstDate.month).trim()} – '
            '${lastDate.day} ${DateUtil.getMonthArabic(lastDate.month).trim()}, ${lastDate.year}'
        : '${DateFormat('MMM dd', 'en_US').format(firstDate)} – '
            '${DateFormat('MMM dd', 'en_US').format(lastDate)}, ${lastDate.year}';

    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 5.w),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Text(
          //   "Doctor Schedule",
          //   style: TextStyle(
          //     fontSize: 24.h,
          //     fontWeight: FontWeight.bold,
          //     color: const Color(0xFF1A1A1A),
          //   ),
          // ),
          SizedBox(height: 16.h),

          // Navigation: < date-pill >
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              _buildNavArrow(
                icon: Icons.chevron_left,
                enabled: currentPage.round() > 0,
                onTap: () => _animateToPage(currentPage.round() - 1),
              ),
              SizedBox(width: 12.w),
              Container(
                padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
                decoration: BoxDecoration(
                  color: AppColors.secondaryLightRedColor,
                  borderRadius: BorderRadius.circular(12.r),
                ),
                child: dateRangeLabel.toText14(
                  weight: FontWeight.w600,
                  color: AppColors.primaryRedColor,
                ),
              ),
              SizedBox(width: 12.w),
              _buildNavArrow(
                icon: Icons.chevron_right,
                enabled: currentPage.round() < weeks.length - 1,
                onTap: () => _animateToPage(currentPage.round() + 1),
              ),
            ],
          ),
          SizedBox(height: 20.h),

          LocaleKeys.weeklyShift.tr(context: context).toText18(
            weight: FontWeight.w600,
            color: AppColors.textColor,
          ),
        ],
      ),
    );
  }

  void _animateToPage(int index) {
    _pageController.animateToPage(
      index.clamp(0, weeks.length - 1),
      duration: const Duration(milliseconds: 300),
      curve: Curves.easeInOut,
    );
  }

  Widget _buildNavArrow({
    required IconData icon,
    required bool enabled,
    required VoidCallback onTap,
  }) {
    return GestureDetector(
      onTap: enabled ? onTap : null,
      child: Container(
        width: 34.w,
        height: 34.w,
        decoration: BoxDecoration(

          borderRadius: BorderRadius.circular(8.h),
          color: enabled ? AppColors.secondaryLightRedColor : AppColors.greyF7Color,
        ),
        child: Icon(
          icon,
          size: 28.h,
          color: enabled ? AppColors.primaryRedColor : AppColors.checkBoxBorderColor,
        ),
      ),
    );
  }

  // ── Week / day views ───────────────────────────────────────────────────────

  Widget _buildWeekView(int weekIndex, bool isArabic) {
    final weekSchedule = weeks[weekIndex];
    return Directionality(
      textDirection: isArabic ? ui.TextDirection.rtl : ui.TextDirection.ltr,
      child: ListView.builder(
        // primary: false detaches this ListView from the PrimaryScrollController
        // so it doesn't fight with CollapsingListView's outer CustomScrollView.
        primary: false,
        physics: const ClampingScrollPhysics(),
        padding: EdgeInsets.only(top: 8.h, bottom: 24.h),
        itemCount: weekSchedule.length,
        itemBuilder: (context, dayIndex) => _buildDayCard(context, weekSchedule[dayIndex]),
      ),
    );
  }

  Widget _buildDayCard(BuildContext context, Map<String, dynamic> daySchedule) {
    final date = DateUtil.convertStringToDate(daySchedule['Date'] as String);
    final hasFreeSlots = !(daySchedule['fullDay'] as bool? ?? true);
    final workingHours = (daySchedule['WorkingHours'] as String?) ?? '';
    final isOff = workingHours.isEmpty ||
        workingHours.toLowerCase().contains('off') ||
        workingHours.toLowerCase().contains('not available');

    final shifts = workingHours.split(',').map((s) => s.trim()).where((s) => s.isNotEmpty).toList();

    return Material(
      color: Colors.transparent,
      child: InkWell(
        onTap: hasFreeSlots ? () => getIt.get<NavigationService>().pop() : null,
        borderRadius: BorderRadius.circular(20.r),
        child: Container(
          margin: EdgeInsets.only(bottom: 12.h, left: 5.w, right: 5.w),
          padding: EdgeInsets.symmetric(horizontal: 18.w, vertical: 16.h),
          decoration: BoxDecoration(
            color: AppColors.whiteColor,
            borderRadius: BorderRadius.circular(20.r),
            boxShadow: [
              BoxShadow(
                blurRadius: 16,
                spreadRadius: 0,
                color: Colors.black.withValues(alpha: 0.02),
                offset: const Offset(0, 6),
              ),
            ],
          ),
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              // Left — day name + short date
              Expanded(
                flex: 2,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    daySchedule['DayName'].toString().toText16(
                      weight: FontWeight.w700,
                      color: AppColors.textColor,
                    ),
                    SizedBox(height: 4.h),
                    _getDayMonth(date).toText13(
                      color: AppColors.greyTextColorLight,
                    ),
                  ],
                ),
              ),

              // Right — time slots or "Off"
              if (isOff)
                LocaleKeys.dayOff.tr(context: context).toText14(
                  weight: FontWeight.w500,
                  color: AppColors.greyTextColorLight,
                )
              else
                Expanded(
                  flex: 3,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      for (var i = 0; i < shifts.length; i++) ...[
                        shifts[i].toText14(
                          weight: FontWeight.w500,
                          color: AppColors.textColor,
                        ),
                        if (i < shifts.length - 1) SizedBox(height: 6.h),
                      ],
                    ],
                  ),
                ),
            ],
          ),
        ),
      ),
    );
  }

  // ── Helpers ────────────────────────────────────────────────────────────────

  bool _hasFreeSlot(String jsonDate) {
    if (jsonDate.isEmpty) return false;
    final date = DateUtil.convertStringToDate(jsonDate);
    final scheduleDay = DateTime(date.year, date.month, date.day);

    for (final event in freeSlots) {
      try {
        final eventDate = DateUtil.convertStringToDate(event);
        final nDate = DateTime(eventDate.year, eventDate.month, eventDate.day);
        if (nDate.millisecondsSinceEpoch == scheduleDay.millisecondsSinceEpoch) return true;
      } catch (_) {
        continue;
      }
    }
    return false;
  }

  String _getDayMonth(DateTime dateTime) {
    final isArabic = appState.isArabic();
    if (isArabic) {
      return '${dateTime.day} ${DateUtil.getMonthArabic(dateTime.month)}';
    }
    return '${dateTime.day} ${DateUtil.getMonth(dateTime.month).substring(0, 3)}';
  }
}

