// ignore_for_file: library_private_types_in_public_api, deprecated_member_use, depend_on_referenced_packages, unnecessary_import
import 'package:didvan/views/ai/ai_state.dart';
import 'package:didvan/views/widgets/hoshan_app_bar.dart';
import 'package:didvan/views/widgets/state_handlers/state_handler.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/main.dart';
import 'package:didvan/models/ai/ai_chat_args.dart';
import 'package:didvan/models/ai/bots_model.dart';
import 'package:didvan/models/ai/chats_model.dart';
import 'package:didvan/models/ai/files_model.dart';
import 'package:didvan/models/ai/messages_model.dart';
import 'package:didvan/models/ai/ai_model_enum.dart';
import 'package:didvan/models/enums.dart';
import 'package:didvan/models/view/alert_data.dart';
import 'package:didvan/providers/user.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/media/media.dart';
import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/utils/date_time.dart';
import 'package:didvan/utils/extension.dart';
import 'package:didvan/views/ai/ai_chat_state.dart';
import 'package:didvan/views/ai/history_ai_chat_state.dart';
import 'package:didvan/views/ai/widgets/ai_message_bar.dart';
import 'package:didvan/views/ai/widgets/audio_wave.dart';
import 'package:didvan/views/ai/widgets/hoshan_drawer.dart';
import 'package:didvan/views/widgets/didvan/didvan_markdown.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:didvan/views/widgets/marquee_text.dart';
import 'package:didvan/views/widgets/skeleton_image.dart';
import 'package:didvan/views/widgets/video/chat_video_player.dart';
import 'package:didvan/views/widgets/video/custome_controls.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:persian_number_utility/persian_number_utility.dart';
import 'package:provider/provider.dart';

class AiChatPage extends StatefulWidget {
  final AiChatArgs args;
  const AiChatPage({Key? key, required this.args}) : super(key: key);
  @override
  _AiChatPageState createState() => _AiChatPageState();
}

class _AiChatPageState extends State<AiChatPage> with TickerProviderStateMixin {
  final GlobalKey<ScaffoldState> scaffKey = GlobalKey<ScaffoldState>();
  FocusNode focusNode = FocusNode();
  BotsModel? _searchBot;
  BotsModel? _geminiBot;
  BotsModel? _grokBot;
  bool _isSearchMode = false;
  AiModel _selectedModel = AiModel.chatGPT;
  late BotsModel _currentBot;

  late AnimationController _fadeController;
  late AnimationController _messageController;
  late Animation<double> _fadeAnimation;
  late Animation<Offset> _slideAnimation;

  @override
  void didUpdateWidget(covariant AiChatPage oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.args.bot.id != oldWidget.args.bot.id) {
      debugPrint("--- AI CHAT PAGE: Bot Updated ---");
      debugPrint(
          "Bot ID: ${widget.args.bot.id}, Bot Name: ${widget.args.bot.name}");
      debugPrint("---------------------------------");
      setState(() {
        _currentBot = widget.args.bot;
        _isSearchMode = _currentBot.id == 36;
      });
      final state = context.read<AiChatState>();
      state.clearChat();
      if (widget.args.bot.id == 35) {
        state.fetchSuggestedQuestions();
      }
      if (widget.args.chat != null) {
        state.chatId = widget.args.chat!.id!;
        state.chat = widget.args.chat;
        state.getAllMessages(state.chatId!);
      }
      if (widget.args.prompts != null) {
        state.messages.add(MessageModel(
            dateTime: DateTime.now()
                .subtract(const Duration(minutes: 210))
                .toIso8601String(),
            prompts: [widget.args.prompts!]));
        state.message.clear();
        state.update();
        state.postMessage(widget.args.bot, widget.args.assistantsName != null);
      }
    }
  }

  @override
  void initState() {
    super.initState();

    _fadeController = AnimationController(
      duration: const Duration(milliseconds: 600),
      vsync: this,
    );

    _messageController = AnimationController(
      duration: const Duration(milliseconds: 400),
      vsync: this,
    );

    _fadeAnimation = CurvedAnimation(
      parent: _fadeController,
      curve: Curves.easeIn,
    );

    _slideAnimation = Tween<Offset>(
      begin: const Offset(0, 0.1),
      end: Offset.zero,
    ).animate(CurvedAnimation(
      parent: _messageController,
      curve: Curves.easeOutCubic,
    ));

    _fadeController.forward();
    _messageController.forward();

    debugPrint("--- AI CHAT PAGE: Init ---");
    debugPrint(
        "Bot ID: ${widget.args.bot.id}, Bot Name: ${widget.args.bot.name}");
    debugPrint("----------------------------");
    _currentBot = widget.args.bot;
    _isSearchMode = _currentBot.id == 36;
    final state = context.read<AiChatState>();
    if (widget.args.chat != null) {
      state.chatId = widget.args.chat!.id!;
      state.chat = widget.args.chat;
    }
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      try {
        final bots = context.read<HistoryAiChatState>().bots;
        if (mounted) {
          setState(() {
            _searchBot = bots.firstWhere((b) => b.id == 36);
            try {
              _geminiBot = bots.firstWhere((b) =>
                  b.id == 35 &&
                  (b.name?.toLowerCase().contains('gemini') ?? false));
            } catch (e) {
              _geminiBot = BotsModel(
                id: 35,
                name: 'Gemini',
                responseType: 'text',
                attachmentType: [
                  'audio',
                  'image',
                  'pdf',
                  'csv',
                  'doc',
                  'docx',
                  'xls',
                  'xlsx'
                ],
                attachment: 1,
              );
            }
            try {
              _grokBot = bots.firstWhere((b) =>
                  b.id == 35 &&
                  (b.name?.toLowerCase().contains('grok') ?? false));
            } catch (e) {
              _grokBot = BotsModel(
                id: 35,
                name: 'Grok',
                responseType: 'text',
                attachmentType: [
                  'audio',
                  'image',
                  'pdf',
                  'csv',
                  'doc',
                  'docx',
                  'xls',
                  'xlsx'
                ],
                attachment: 1,
              );
            }
          });
        }
      } catch (e) {
        if (mounted) {
          setState(() {
            _searchBot = BotsModel(
              id: 36,
              name: 'GPT-4o-mini-search',
              responseType: 'text',
              attachmentType: [
                'audio',
                'image',
                'pdf',
                'csv',
                'doc',
                'docx',
                'xls',
                'xlsx'
              ],
              attachment: 1,
            );
            _geminiBot = BotsModel(
              id: 35,
              name: 'Gemini',
              responseType: 'text',
              attachmentType: [
                'audio',
                'image',
                'pdf',
                'csv',
                'doc',
                'docx',
                'xls',
                'xlsx'
              ],
              attachment: 1,
            );
            _grokBot = BotsModel(
              id: 35,
              name: 'Grok',
              responseType: 'text',
              attachmentType: [
                'audio',
                'image',
                'pdf',
                'csv',
                'doc',
                'docx',
                'xls',
                'xlsx'
              ],
              attachment: 1,
            );
          });
          debugPrint(
              "Search bot (ID 36) not found in History state: $e. Using fallback with audio support.");
        }
      }
      if (widget.args.bot.id == 35) {
        state.fetchSuggestedQuestions();
      }
      if (state.chatId != null) {
        state.getAllMessages(state.chatId!).then((value) => Future.delayed(
              const Duration(milliseconds: 100),
              () {
                focusNode.requestFocus();
                if (state.messages.isNotEmpty) {
                  state.scrollController.animateTo(
                    state.scrollController.position.maxScrollExtent,
                    duration: const Duration(milliseconds: 300),
                    curve: Curves.easeOut,
                  );
                }
              },
            ));
      } else {
        state.appState = AppState.idle;
        Future.delayed(
          const Duration(milliseconds: 100),
          () => focusNode.requestFocus(),
        );
      }
      if (widget.args.prompts != null) {
        state.messages.add(MessageModel(
            dateTime: DateTime.now()
                .subtract(const Duration(minutes: 210))
                .toIso8601String(),
            prompts: [widget.args.prompts!]));
        state.message.clear();
        state.update();
        await state.postMessage(
            widget.args.bot, widget.args.assistantsName != null);
        Future.delayed(const Duration(milliseconds: 100), () {
          state.scrollController.animateTo(
            state.scrollController.position.maxScrollExtent,
            duration: const Duration(milliseconds: 300),
            curve: Curves.easeOut,
          );
        });
      }
    });
  }

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

  BotsModel _getSelectedBot() {
    switch (_selectedModel) {
      case AiModel.gemini:
        return _geminiBot ?? _currentBot;
      case AiModel.grok:
        return _grokBot ?? _currentBot;
      case AiModel.chatGPT:
      default:
        return _currentBot;
    }
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        if (context.read<HistoryAiChatState>().refresh) {
          context.read<HistoryAiChatState>().getChats();
          context.read<HistoryAiChatState>().refresh = false;
        }
        context.read<AiState>().endChat();

        await Future.delayed(Duration.zero);

        return true;
      },
      child: Consumer<AiChatState>(
        builder: (context, state, child) => Scaffold(
          appBar: HoshanAppBar(
            onBack: () async {
              if (context.read<HistoryAiChatState>().refresh) {
                context.read<HistoryAiChatState>().getChats();
                context.read<HistoryAiChatState>().refresh = false;
              }
              context.read<AiState>().endChat();

              await Future.delayed(const Duration(milliseconds: 50));

              if (context.mounted) {
                Navigator.pop(context);
              }
            },
            withActions: false,
          ),
          key: scaffKey,
          resizeToAvoidBottomInset: true,
          drawer: HoshanDrawer(
            scaffKey: scaffKey,
          ),
          body: StateHandler<AiChatState>(
            state: state,
            onRetry: () {
              if (state.chatId != null) {
                state.getAllMessages(state.chatId!);
              }
              if (widget.args.bot.id == 35) {
                state.fetchSuggestedQuestions();
              }
            },
            builder: (context, state) {
              final userProvider = context.watch<UserProvider>();
              return SingleChildScrollView(
                reverse: true,
                controller: state.scrollController,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    if (state.messages.isEmpty)
                      FadeTransition(
                        opacity: _fadeAnimation,
                        child: SlideTransition(
                          position: _slideAnimation,
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.center,
                            children: [
                              const SizedBox(height: 90),
                              userProvider.isLoadingWelcome
                                  ? const SizedBox(height: 20)
                                  : userProvider.welcomeMessage != null
                                      ? TweenAnimationBuilder<double>(
                                          duration:
                                              const Duration(milliseconds: 800),
                                          tween: Tween(begin: 0.0, end: 1.0),
                                          curve: Curves.easeOut,
                                          builder: (context, value, child) {
                                            return Opacity(
                                              opacity: value,
                                              child: Transform.scale(
                                                scale: 0.8 + (0.2 * value),
                                                child: child,
                                              ),
                                            );
                                          },
                                          child: Padding(
                                            padding: const EdgeInsets.only(
                                                bottom: 12.0,
                                                left: 24,
                                                right: 24),
                                            child: Center(
                                              child: DidvanText(
                                                userProvider.welcomeMessage!,
                                                textAlign: TextAlign.center,
                                                fontSize: 18,
                                                fontWeight: FontWeight.bold,
                                                color: const Color.fromARGB(
                                                    255, 0, 126, 167),
                                              ),
                                            ),
                                          ),
                                        )
                                      : const SizedBox(height: 20),
                              TweenAnimationBuilder<double>(
                                duration: const Duration(milliseconds: 1000),
                                tween: Tween(begin: 0.0, end: 1.0),
                                curve: Curves.easeOut,
                                builder: (context, value, child) {
                                  return Opacity(
                                    opacity: value,
                                    child: Transform.translate(
                                      offset: Offset(0, 20 * (1 - value)),
                                      child: child,
                                    ),
                                  );
                                },
                                child: const Text(
                                  'چطور می‌تونم کمکت کنم؟',
                                  style: TextStyle(
                                    color: Color.fromARGB(255, 0, 53, 70),
                                    fontSize: 16,
                                    fontWeight: FontWeight.bold,
                                  ),
                                ),
                              ),
                              const SizedBox(height: 70),
                              if (widget.args.bot.id == 35)
                                Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    const SizedBox(height: 20),
                                    Padding(
                                      padding: const EdgeInsets.symmetric(
                                          horizontal: 24.0),
                                      child: Row(
                                        children: [
                                          const SizedBox(width: 7),
                                          SvgPicture.asset(
                                            'lib/assets/icons/message-question.svg',
                                            height: 25,
                                            color: const Color.fromARGB(
                                                255, 0, 126, 167),
                                          ),
                                          const SizedBox(width: 7),
                                          const DidvanText(
                                            'سوالات پیشنهادی:',
                                            fontSize: 16,
                                            fontWeight: FontWeight.normal,
                                            color: Color.fromARGB(
                                                255, 0, 126, 167),
                                          ),
                                        ],
                                      ),
                                    ),
                                    const SizedBox(height: 12),
                                    state.isLoadingQuestions
                                        ? Center(
                                            child: SpinKitThreeBounce(
                                              color: Theme.of(context)
                                                  .colorScheme
                                                  .primary,
                                              size: 18,
                                            ),
                                          )
                                        : state.suggestedQuestions.isEmpty
                                            ? Padding(
                                                padding:
                                                    const EdgeInsets.symmetric(
                                                        horizontal: 24.0),
                                                child: Center(
                                                  child: DidvanText(
                                                    'سوالی برای پیشنهاد وجود ندارد.',
                                                    fontSize: 12,
                                                    color: Theme.of(context)
                                                        .colorScheme
                                                        .caption,
                                                  ),
                                                ),
                                              )
                                            : ListView.builder(
                                                shrinkWrap: true,
                                                physics:
                                                    const NeverScrollableScrollPhysics(),
                                                itemCount: state
                                                    .suggestedQuestions.length,
                                                itemBuilder: (context, index) {
                                                  final question =
                                                      state.suggestedQuestions[
                                                          index];
                                                  return TweenAnimationBuilder<
                                                      double>(
                                                    duration: Duration(
                                                        milliseconds: 400 +
                                                            (index * 100)),
                                                    tween: Tween(
                                                        begin: 0.0, end: 1.0),
                                                    curve: Curves.easeOut,
                                                    builder: (context, value,
                                                        child) {
                                                      return Opacity(
                                                        opacity: value,
                                                        child:
                                                            Transform.translate(
                                                          offset: Offset(
                                                              30 * (1 - value),
                                                              0),
                                                          child: child,
                                                        ),
                                                      );
                                                    },
                                                    child: InkWell(
                                                      onTap: () {
                                                        if (state.messages
                                                                .isNotEmpty &&
                                                            DateTime.parse(state
                                                                    .messages
                                                                    .last
                                                                    .dateTime)
                                                                .toPersianDateStr()
                                                                .contains(DateTime.parse(DateTime
                                                                            .now()
                                                                        .subtract(const Duration(
                                                                            minutes:
                                                                                210))
                                                                        .toIso8601String())
                                                                    .toPersianDateStr())) {
                                                          state.messages.last
                                                              .prompts
                                                              .add(Prompts(
                                                            error: false,
                                                            text: question,
                                                            fileLocal: null,
                                                            finished: true,
                                                            role: 'user',
                                                            createdAt: DateTime
                                                                    .now()
                                                                .subtract(
                                                                    const Duration(
                                                                        minutes:
                                                                            210))
                                                                .toIso8601String(),
                                                          ));
                                                        } else {
                                                          state.messages.add(MessageModel(
                                                              dateTime: DateTime
                                                                      .now()
                                                                  .subtract(
                                                                      const Duration(
                                                                          minutes:
                                                                              210))
                                                                  .toIso8601String(),
                                                              prompts: [
                                                                Prompts(
                                                                  error: false,
                                                                  text:
                                                                      question,
                                                                  finished:
                                                                      true,
                                                                  fileLocal:
                                                                      null,
                                                                  role: 'user',
                                                                  createdAt: DateTime
                                                                          .now()
                                                                      .subtract(const Duration(
                                                                          minutes:
                                                                              210))
                                                                      .toIso8601String(),
                                                                )
                                                              ]));
                                                        }
                                                        state.message.clear();
                                                        state.update();
                                                        state.postMessage(
                                                            _currentBot,
                                                            widget.args
                                                                    .assistantsName !=
                                                                null);
                                                        Future.delayed(
                                                            const Duration(
                                                                milliseconds:
                                                                    100), () {
                                                          state.scrollController
                                                              .animateTo(
                                                            state
                                                                .scrollController
                                                                .position
                                                                .maxScrollExtent,
                                                            duration:
                                                                const Duration(
                                                                    milliseconds:
                                                                        300),
                                                            curve:
                                                                Curves.easeOut,
                                                          );
                                                        });
                                                      },
                                                      child: Column(
                                                        children: [
                                                          Container(
                                                            margin:
                                                                const EdgeInsets
                                                                    .symmetric(
                                                                    horizontal:
                                                                        24,
                                                                    vertical:
                                                                        4),
                                                            child: DidvanText(
                                                              question,
                                                              fontSize: 12,
                                                              color: const Color
                                                                  .fromARGB(
                                                                  255,
                                                                  102,
                                                                  102,
                                                                  102),
                                                            ),
                                                          ),
                                                          const Padding(
                                                            padding: EdgeInsets
                                                                .fromLTRB(110,
                                                                    5, 20, 5),
                                                            child: Divider(
                                                              height: 1,
                                                              color: Color
                                                                  .fromARGB(
                                                                      255,
                                                                      210,
                                                                      210,
                                                                      210),
                                                            ),
                                                          ),
                                                        ],
                                                      ),
                                                    ),
                                                  );
                                                },
                                              ),
                                    const SizedBox(height: 10),
                                  ],
                                )
                              else
                                const SizedBox(height: 20),
                            ],
                          ),
                        ),
                      ),
                    if (state.messages.isNotEmpty)
                      ListView.builder(
                        itemCount: state.messages.length,
                        shrinkWrap: true,
                        physics: const NeverScrollableScrollPhysics(),
                        itemBuilder: (context, mIndex) {
                          final prompts = state.messages[mIndex].prompts;
                          final time = state.messages[mIndex].dateTime;
                          return Column(
                            children: [
                              timeLabel(context, time),
                              ListView.builder(
                                itemCount: prompts.length,
                                shrinkWrap: true,
                                physics: const NeverScrollableScrollPhysics(),
                                itemBuilder: (context, index) {
                                  final message = prompts[index];
                                  return messageBubble(
                                      message, context, state, index, mIndex);
                                },
                              ),
                            ],
                          );
                        },
                      ),
                  ],
                ),
              );
            },
          ),
          bottomNavigationBar: Padding(
            padding: EdgeInsets.only(
              bottom: _currentBot.id == 35
                  ? MediaQuery.of(context).viewInsets.bottom
                  : (MediaQuery.of(context).viewInsets.bottom - 72.0)
                      .clamp(0.0, double.infinity),
            ),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                AiMessageBar(
                  bot: _isSearchMode && _searchBot != null
                      ? _searchBot!
                      : _getSelectedBot(),
                  attch: widget.args.attach,
                  assistantsName: widget.args.assistantsName,
                  showSearchToggle: _currentBot.id == 35 && _searchBot != null,
                  isSearchMode: _isSearchMode,
                  onSearchModeToggled: (bool isSearchOn) {
                    if (_searchBot == null) return;
                    setState(() {
                      _isSearchMode = isSearchOn;
                    });
                  },
                  showModelSelector: _currentBot.id == 35 &&
                      _geminiBot != null &&
                      _grokBot != null,
                  selectedModel: _selectedModel,
                  onModelChanged: (AiModel model) {
                    setState(() {
                      _selectedModel = model;
                    });
                  },
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Center timeLabel(BuildContext context, String time) {
    return Center(
      child: Container(
        margin: const EdgeInsets.symmetric(vertical: 12),
        padding: const EdgeInsets.all(4),
        decoration: BoxDecoration(
          color: Theme.of(context).colorScheme.splash,
          borderRadius: DesignConfig.lowBorderRadius,
        ),
        child: DidvanText(
          DateTime.parse(time).toPersianDateStr(),
          style: Theme.of(context).textTheme.labelSmall,
          color: DesignConfig.isDark
              ? Theme.of(context).colorScheme.white
              : Theme.of(context).colorScheme.black,
        ),
      ),
    );
  }

  Widget messageBubble(Prompts message, BuildContext context, AiChatState state,
      int index, int mIndex) {
    FilesModel? file = message.fileLocal ??
        (message.file == null
            ? null
            : FilesModel(message.file.toString().replaceAll(' ', ''),
                duration: message.duration != null
                    ? Duration(seconds: message.duration!)
                    : null,
                audio: message.audio,
                video: message.video));

    final isUser = message.role.toString().contains('user');

    return TweenAnimationBuilder<double>(
      duration: Duration(milliseconds: 300 + (index * 50)),
      tween: Tween(begin: 0.0, end: 1.0),
      curve: Curves.easeOut,
      builder: (context, value, child) {
        return Opacity(
          opacity: value,
          child: Transform.translate(
            offset: Offset(isUser ? -20 * (1 - value) : 20 * (1 - value), 0),
            child: child,
          ),
        );
      },
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 4),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: message.role.toString().contains('user')
              ? CrossAxisAlignment.start
              : CrossAxisAlignment.end,
          children: [
            Row(
              mainAxisAlignment: message.role.toString().contains('user')
                  ? MainAxisAlignment.start
                  : MainAxisAlignment.end,
              children: [
                Container(
                  constraints: BoxConstraints(
                      maxWidth: MediaQuery.sizeOf(context).width / 1.3),
                  decoration: BoxDecoration(
                    borderRadius: DesignConfig.mediumBorderRadius.copyWith(
                      bottomLeft: !message.role.toString().contains('user')
                          ? Radius.zero
                          : null,
                      bottomRight: message.role.toString().contains('user')
                          ? Radius.zero
                          : null,
                    ),
                    color: message.error != null && message.error!
                        ? Theme.of(context).colorScheme.error.withOpacity(0.4)
                        : (message.role.toString().contains('user')
                                ? Theme.of(context).colorScheme.surface
                                : Theme.of(context).colorScheme.focused)
                            .withOpacity(0.9),
                    border: Border.all(
                      color: Theme.of(context).colorScheme.border,
                      width: 0.5,
                    ),
                  ),
                  child: Container(
                    child: message.finished != null && !message.finished!
                        ? Column(
                            children: [
                              ValueListenableBuilder<Stream<String>>(
                                valueListenable: state.messageOnstream,
                                builder: (context, value, child) {
                                  return StreamBuilder<String>(
                                    stream: value,
                                    builder: (context, snapshot) {
                                      if (!snapshot.hasData) {
                                        return const SizedBox();
                                      }
                                      return Padding(
                                        padding: const EdgeInsets.symmetric(
                                            vertical: 8.0, horizontal: 16),
                                        child: Directionality(
                                          textDirection: snapshot.data
                                                  .toString()
                                                  .startsWithEnglish()
                                              ? TextDirection.ltr
                                              : TextDirection.rtl,
                                          child: DidvanMarkdownText(
                                            text: "${snapshot.data}...",
                                          ),
                                        ),
                                      );
                                    },
                                  );
                                },
                              ),
                              Padding(
                                padding:
                                    const EdgeInsets.symmetric(vertical: 8.0),
                                child: SpinKitThreeBounce(
                                  color: Theme.of(context).colorScheme.primary,
                                  size: 18,
                                ),
                              ),
                            ],
                          )
                        : Column(
                            children: [
                              if (file != null)
                                (file.isAudio())
                                    ? Padding(
                                        padding: const EdgeInsets.symmetric(
                                            horizontal: 16, vertical: 8),
                                        child: AudioWave(
                                          file: file.path,
                                          totalDuration: file.duration,
                                        ),
                                      )
                                    : file.isVideo()
                                        ? Padding(
                                            padding: const EdgeInsets.fromLTRB(
                                                16, 16, 16, 0),
                                            child: ClipRRect(
                                              borderRadius:
                                                  DesignConfig.lowBorderRadius,
                                              child: ChatVideoPlayer(
                                                src: RequestHelper.baseUrl +
                                                    file.path,
                                                custome: const CustomControls(),
                                              ),
                                            ),
                                          )
                                        : file.isImage()
                                            ? Padding(
                                                padding:
                                                    const EdgeInsets.all(8.0),
                                                child: messageImage(file),
                                              )
                                            : Padding(
                                                padding:
                                                    const EdgeInsets.all(8.0),
                                                child: messageFile(
                                                    context, message, state),
                                              ),
                              if (message.text != null &&
                                  message.text!.isNotEmpty &&
                                  ((message.audio == null ||
                                      (message.audio != null &&
                                          !message.audio!))))
                                Padding(
                                  padding: const EdgeInsets.symmetric(
                                      vertical: 8.0, horizontal: 16),
                                  child: Directionality(
                                    textDirection: message.text
                                            .toString()
                                            .startsWithEnglish()
                                        ? TextDirection.ltr
                                        : TextDirection.rtl,
                                    child: DidvanMarkdownText(
                                      text: message.text.toString(),
                                    ),
                                  ),
                                ),
                              Padding(
                                padding:
                                    const EdgeInsets.symmetric(horizontal: 8.0),
                                child: Row(
                                  mainAxisAlignment: MainAxisAlignment.end,
                                  children: [
                                    if (message.role
                                            .toString()
                                            .contains('user') &&
                                        widget.args.assistantsName == null)
                                      PopupMenuButton(
                                        offset: const Offset(0, 46),
                                        onSelected: (value) async {
                                          navigatorKey.currentState!.pushNamed(
                                            Routes.aiChat,
                                            arguments: AiChatArgs(
                                              bot: value,
                                              prompts: message,
                                              isTool: widget.args.isTool ??
                                                  context
                                                      .read<
                                                          HistoryAiChatState>()
                                                      .bots,
                                            ),
                                          );
                                        },
                                        itemBuilder: (BuildContext context) {
                                          final bots = widget.args.isTool ??
                                              context
                                                  .read<HistoryAiChatState>()
                                                  .bots;
                                          return <PopupMenuEntry>[
                                            ...List.generate(
                                              bots.length,
                                              (index) => PopupMenuItem(
                                                value: bots[index],
                                                height: 72,
                                                child: Container(
                                                  constraints:
                                                      const BoxConstraints(
                                                          maxWidth: 200),
                                                  child: Row(
                                                    children: [
                                                      SkeletonImage(
                                                        imageUrl: bots[index]
                                                            .image
                                                            .toString(),
                                                        width: 42,
                                                        height: 42,
                                                        borderRadius:
                                                            BorderRadius
                                                                .circular(360),
                                                      ),
                                                      const SizedBox(width: 12),
                                                      Expanded(
                                                        child: Directionality(
                                                          textDirection:
                                                              TextDirection.ltr,
                                                          child: DidvanText(
                                                            bots[index]
                                                                .name
                                                                .toString(),
                                                            maxLines: 1,
                                                            overflow:
                                                                TextOverflow
                                                                    .ellipsis,
                                                          ),
                                                        ),
                                                      ),
                                                    ],
                                                  ),
                                                ),
                                              ),
                                            ),
                                          ];
                                        },
                                        child: const SizedBox(),
                                      ),
                                    if (message.role
                                            .toString()
                                            .contains('user') &&
                                        index ==
                                            state.messages[mIndex].prompts
                                                    .length -
                                                2 &&
                                        (_currentBot.editable != null &&
                                            _currentBot.editable!))
                                      Padding(
                                        padding: const EdgeInsets.all(8.0),
                                        child: InkWell(
                                          onTap: () async {
                                            state.isEdite = true;
                                            state.message.text =
                                                message.text.toString();
                                            state.update();
                                          },
                                          child: Icon(
                                            Icons.edit_outlined,
                                            size: 18,
                                            color: Theme.of(context)
                                                .colorScheme
                                                .focusedBorder,
                                          ),
                                        ),
                                      ),
                                    if (message.file != null && kIsWeb)
                                      Padding(
                                        padding: const EdgeInsets.all(8.0),
                                        child: InkWell(
                                          onTap: () async {
                                            final url =
                                                '${RequestHelper.baseUrl + message.file.toString()}?accessToken=${RequestService.token}';
                                            MediaService.downloadFileFromWeb(
                                                url);
                                          },
                                          child: Icon(
                                            DidvanIcons.download_solid,
                                            size: 18,
                                            color: Theme.of(context)
                                                .colorScheme
                                                .focusedBorder,
                                          ),
                                        ),
                                      ),
                                    if (message.file != null && !kIsWeb)
                                      Padding(
                                        padding: const EdgeInsets.all(8.0),
                                        child: InkWell(
                                          onTap: () async {
                                            debugPrint(
                                                "Download button tapped on iOS");
                                            final url =
                                                '${RequestHelper.baseUrl + message.file.toString()}?accessToken=${RequestService.token}';
                                            await MediaService.downloadFile(url,
                                                name: message.fileName);
                                          },
                                          child: Icon(
                                            DidvanIcons.download_solid,
                                            size: 18,
                                            color: Theme.of(context)
                                                .colorScheme
                                                .focusedBorder,
                                          ),
                                        ),
                                      ),
                                    if (message.error != null && message.error!)
                                      Padding(
                                        padding: const EdgeInsets.all(8.0),
                                        child: InkWell(
                                          onTap: () async {
                                            state.messages.last.prompts
                                                .remove(message);
                                            state.messages.last.prompts.add(
                                                message.copyWith(error: false));
                                            state.file = file;
                                            state.update();
                                            final botToUse = _isSearchMode &&
                                                    _searchBot != null
                                                ? _searchBot!
                                                : _getSelectedBot();
                                            await state.postMessage(
                                                botToUse,
                                                widget.args.assistantsName !=
                                                    null);
                                            Future.delayed(
                                                const Duration(
                                                    milliseconds: 100), () {
                                              state.scrollController.animateTo(
                                                state.scrollController.position
                                                    .maxScrollExtent,
                                                duration: const Duration(
                                                    milliseconds: 300),
                                                curve: Curves.easeOut,
                                              );
                                            });
                                          },
                                          child: Icon(
                                            DidvanIcons.refresh_solid,
                                            size: 18,
                                            color: Theme.of(context)
                                                .colorScheme
                                                .focusedBorder,
                                          ),
                                        ),
                                      ),
                                    if (message.text != null &&
                                        message.text!.isNotEmpty &&
                                        (file == null || !file.isImage()))
                                      Padding(
                                        padding: const EdgeInsets.all(8.0),
                                        child: InkWell(
                                          onTap: () async {
                                            await Clipboard.setData(
                                                ClipboardData(
                                                    text: state.messages[mIndex]
                                                        .prompts[index].text
                                                        .toString()));
                                            Future.delayed(
                                              Duration.zero,
                                              () => ActionSheetUtils(context)
                                                  .showAlert(
                                                AlertData(
                                                  message:
                                                      "متن با موفقیت کپی شد",
                                                  aLertType: ALertType.success,
                                                ),
                                              ),
                                            );
                                          },
                                          child: Icon(
                                            DidvanIcons.copy_regular,
                                            size: 18,
                                            color: Theme.of(context)
                                                .colorScheme
                                                .focusedBorder,
                                          ),
                                        ),
                                      ),
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: InkWell(
                                        onTap: () async {
                                          if (message.id != null) {
                                            state.deleteMessage(
                                                message.id!, mIndex, index);
                                          } else {
                                            state.messages[mIndex].prompts
                                                .removeAt(index);
                                            state.update();
                                          }
                                        },
                                        child: Icon(
                                          DidvanIcons.trash_solid,
                                          size: 18,
                                          color: Theme.of(context)
                                              .colorScheme
                                              .focusedBorder,
                                        ),
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                              const SizedBox(height: 8),
                            ],
                          ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 4),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                DidvanText(
                  DateTimeUtils.timeWithAmPm(message.createdAt.toString()),
                  style: Theme.of(context).textTheme.labelSmall,
                  color: Theme.of(context).colorScheme.caption,
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Container messageFile(
      BuildContext context, Prompts message, AiChatState state) {
    final String fileName = message.fileName ?? message.fileLocal?.name ?? '';
    return Container(
      decoration: BoxDecoration(
        borderRadius: DesignConfig.mediumBorderRadius,
        color: Theme.of(context).colorScheme.border,
      ),
      padding: const EdgeInsets.fromLTRB(12, 8, 12, 8),
      margin: const EdgeInsets.fromLTRB(8, 8, 8, 0),
      child: Row(
        children: [
          const Icon(Icons.file_copy),
          const SizedBox(width: 12),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                SizedBox(
                  width: MediaQuery.sizeOf(context).width,
                  child: MarqueeText(
                    text: fileName,
                    style: const TextStyle(fontSize: 14),
                    stop: const Duration(seconds: 3),
                    textDirection: fileName.startsWithEnglish()
                        ? TextDirection.ltr
                        : TextDirection.rtl,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget messageImage(FilesModel file) {
    return GestureDetector(
      onTap: () => ActionSheetUtils(context)
          .openInteractiveViewer(context, file.path, !file.isNetwork()),
      child: file.isNetwork()
          ? file.path.startsWith('blob:')
              ? ClipRRect(
                  borderRadius: DesignConfig.lowBorderRadius,
                  child: Image.network(file.path),
                )
              : SkeletonImage(
                  pWidth: MediaQuery.sizeOf(context).width / 1,
                  pHeight: MediaQuery.sizeOf(context).height / 6,
                  imageUrl: file.path,
                )
          : ClipRRect(
              borderRadius: DesignConfig.lowBorderRadius,
              child: Image.file(file.main),
            ),
    );
  }
}
