import 'dart:convert';

import 'package:electronic_assistant/base/base_controller.dart';
import 'package:electronic_assistant/data/bean/agenda.dart';
import 'package:electronic_assistant/data/bean/chat_item.dart';
import 'package:electronic_assistant/data/bean/file_chat_item.dart';
import 'package:electronic_assistant/data/bean/progressing_chat_item.dart';
import 'package:electronic_assistant/data/bean/reference_chat_item.dart';
import 'package:electronic_assistant/data/consts/event_report_id.dart';
import 'package:electronic_assistant/data/repositories/account_repository.dart';
import 'package:electronic_assistant/data/repositories/chat_repository.dart';
import 'package:electronic_assistant/data/repositories/talk_repository.dart';
import 'package:electronic_assistant/handler/event_handler.dart';
import 'package:electronic_assistant/module/chat/start/view.dart';
import 'package:electronic_assistant/module/chat/view.dart';
import 'package:electronic_assistant/resource/colors.gen.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:uuid/uuid.dart';

import '../../data/bean/stream_chat_origin_data.dart';
import '../../data/bean/talks.dart';
import '../../data/consts/error_code.dart';
import '../../dialog/model_explain_dialog.dart';
import '../../router/app_pages.dart';
import '../../utils/http_handler.dart';

class ChatController extends BaseController {
  final RefreshController refreshController =
      RefreshController(initialLoadStatus: LoadStatus.loading);
  final ScrollController listScrollController = ScrollController();
  final TextEditingController inputController = TextEditingController();

  final RxList chatItems = [].obs;
  final Rxn<TalkBean> talkInfo = Rxn<TalkBean>();
  final Rxn<Agenda> agenda = Rxn<Agenda>();

  final Rxn<String> chatAiTagId = Rxn<String>();

  ChatFromType? fromType;

  bool isConsumeElectric = false;

  @override
  void onInit() {
    super.onInit();
    loadMoreHistory();
    checkArguments();
    initReport();
  }

  @override
  void onReady() {
    super.onReady();
    if (accountRepository.userInfo.value?.profession == null ||
        accountRepository.userInfo.value?.post == null) {
      showStartSheet();
    } else {
      _showModelExplainDialog();
    }
  }

  void checkArguments() {
    List<dynamic> arguments = Get.arguments ?? [];
    if (arguments.isEmpty) {
      return;
    }
    if (arguments[0] is ChatFromType) {
      fromType = arguments[0];
    }
    if (arguments.length > 2 && arguments[2] is Agenda) {
      agenda.value = arguments[2];
    }
    if (arguments.length > 1 && arguments[1] is TalkBean) {
      talkInfo.value = arguments[1];
      sendInitialMessage();
    } else if (arguments.length > 1 && arguments[1] is String) {
      talkRepository
          .talkInfo(arguments[1])
          .then((response) => talkInfo.value = response.talkInfo)
          .then((_) => sendInitialMessage());
    }
  }

  void sendInitialMessage() {
    final talkInfo = this.talkInfo.value;
    if (talkInfo == null) {
      return;
    }
    chatItems.insert(
        0,
        FileChatItem(talkInfo,
            id: const Uuid().v4(),
            conversationId: "",
            role: "user",
            content: "",
            createTime: DateTime.now().toString()));
    if (agenda.value != null) {
      _sendMessage("以这份谈话为背景，你为我执行“${agenda.value?.content}”这一事项");
    }
  }

  onSendClick() {
    if (inputController.text.isEmpty) {
      return;
    }
    String chatContent = inputController.text;
    inputController.clear();
    _sendMessage(chatContent);
  }

  void onAddFileClick() {
    Get.toNamed(RoutePath.fileSearch)?.then((talkInfo) {
      if (talkInfo is TalkBean) {
        this.talkInfo.value = talkInfo;
        agenda.value = null;
        sendInitialMessage();
      }
    });
  }

  Future<void> loadMoreHistory() {
    bool isEmpty = chatItems.isEmpty;

    return chatRepository
        .chatHistory(chatItems.isEmpty ? null : chatItems.last.id)
        .then((value) => chatItems.addAll(value))
        .whenComplete(() => refreshController.loadComplete())
        .whenComplete(() {
      if (isEmpty) {
        for (var element in chatItems.reversed) {
          if (element is ChatItem && element.role == "assistant") {
            chatAiTagId.value = element.id;
          }
        }
        _scrollToBottom();
      }
    });
  }

  void showStartSheet() {
    if (fromType == ChatFromType.fromMain) {
      EventHandler.report(EventId.event_102001, params: {
        EventId.id: EventId.id_001,
      });
    } else if (fromType == ChatFromType.fromTalkDetail) {
      EventHandler.report(EventId.event_102001, params: {
        EventId.id: EventId.id_002,
      });
    } else if (fromType == ChatFromType.fromAnalysisBtn) {
      EventHandler.report(EventId.event_102001, params: {
        EventId.id: EventId.id_003,
      });
    }
    Get.bottomSheet(const ChatStartPage(),
            isScrollControlled: true,
            barrierColor: ColorName.black55,
            backgroundColor: ColorName.transparent)
        .then((result) {
      if (result == null || result == false) {
        Get.back();
      } else {
        _showModelExplainDialog();
      }
    });
  }

  void _showModelExplainDialog() {
    showModelExplainTipsDialog();
  }

  void _sendMessage(String chatContent) {
    chatItems.insert(0, createUserChatItem(chatContent));

    ProgressingChatItem progressingChatItem = ProgressingChatItem(
      id: const Uuid().v4(),
      conversationId: chatItems.last.conversationId,
      role: "assistant",
      content: "",
      createTime: DateTime.now().toString(),
    );
    chatItems.insert(0, progressingChatItem);

    _scrollToBottom();
    if (talkInfo.value == null) {
      EventHandler.report(EventId.event_102003, params: {
        EventId.id: EventId.id_002,
      });
    } else {
      EventHandler.report(EventId.event_102003, params: {
        EventId.id: EventId.id_001,
      });
    }
    chatRepository
        .streamChat(chatContent,
            talkId: talkInfo.value?.id, agendaId: agenda.value?.id)
        .then((stream) {
      stream.listen((event) {
        try {
          Map<String, dynamic> json = jsonDecode(event.data);
          if (json.isEmpty) {
            return;
          }
          StreamChatOriginData data = StreamChatOriginData.fromJson(json);
          if (data.choices == null || data.choices!.isEmpty) {
            return;
          }
          Delta? delta = data.choices![0].delta;
          if (delta == null) {
            return;
          }
          isConsumeElectric = true;
          progressingChatItem.append(delta.content ?? "");
          chatAiTagId.value = progressingChatItem.id;
        } catch (ignore) {}
      }, onDone: () {
        progressingChatItem.content = progressingChatItem.streamContent.value;
        progressingChatItem.isFinished.value = true;
      }, onError: (error) {
        progressingChatItem.isFailed.value = true;
        progressingChatItem.error.value = "网络错误，请检查网络连接";
        debugPrint("error: $error");
        debugPrintStack();
      });
    }).catchError((error) {
      progressingChatItem.isFailed.value = true;
      if (error is ServerErrorException) {
        progressingChatItem.error.value = error.message ?? "服务出错，请稍后再试";
        if (error.code == ErrorCode.errorCodeNoLogin) {
          Get.toNamed(RoutePath.login)?.then((loginSuccess) async {
            if (loginSuccess != null && loginSuccess) {
              _clearChat();
              await loadMoreHistory();
              _sendMessage(chatContent);
            }
          });
        } else if (error.code == ErrorCode.errorCodeNoProfession) {
          showStartSheet();
        }
      } else {
        progressingChatItem.error.value = "网络错误，请检查网络连接";
        debugPrint("error: $error");
        debugPrintStack();
      }
    });
  }

  void _clearChat() async {
    return chatItems.clear();
  }

  void _scrollToBottom() {
    Future.delayed(const Duration(milliseconds: 300), () {
      listScrollController.animateTo(
        0,
        duration: const Duration(milliseconds: 300),
        curve: Curves.easeOut,
      );
    });
  }

  createUserChatItem(String chatContent) {
    final id = const Uuid().v4();
    final conversationId =
        chatItems.isEmpty ? "" : chatItems.last.conversationId;
    const role = "user";
    final content = chatContent;
    final createTime = DateTime.now().toString();
    final talkInfo = this.talkInfo.value;
    return talkInfo == null
        ? ChatItem(
            id: id,
            conversationId: conversationId,
            role: role,
            content: chatContent,
            createTime: createTime)
        : ReferenceChatItem(
            talkInfo: talkInfo,
            id: id,
            conversationId: conversationId,
            role: role,
            content: content,
            createTime: createTime);
  }

  onDeleteReference() {
    talkInfo.value = null;
    agenda.value = null;
  }

  void initReport() {
    if (fromType == ChatFromType.fromMain) {
      EventHandler.report(EventId.event_102002, params: {
        EventId.id: EventId.id_001,
      });
    } else if (fromType == ChatFromType.fromTalkDetail) {
      EventHandler.report(EventId.event_102002, params: {
        EventId.id: EventId.id_002,
      });
    } else if (fromType == ChatFromType.fromAnalysisBtn) {
      EventHandler.report(EventId.event_102002, params: {
        EventId.id: EventId.id_003,
      });
    }
  }

  @override
  void onClose() {
    super.onClose();
    if (isConsumeElectric) {
      accountRepository.refreshUserInfo();
    }
  }
}
