import 'dart:convert';

import 'package:electronic_assistant/base/base_controller.dart';
import 'package:electronic_assistant/data/bean/chat_item.dart';
import 'package:electronic_assistant/data/bean/progressing_chat_item.dart';
import 'package:electronic_assistant/data/bean/stream_chat_origin_data.dart';
import 'package:electronic_assistant/data/repositories/chat_repository.dart';
import 'package:electronic_assistant/module/chat/start/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 '../../utils/http_handler.dart';

class ChatController extends BaseController {
  final RefreshController refreshController = RefreshController();
  final ScrollController listScrollController = ScrollController();
  final TextEditingController inputController = TextEditingController();

  final RxList chatItems = [].obs;

  var isOpenStart = false;

  @override
  void onReady() {
    super.onReady();
    refreshController.requestLoading();
  }

  void loadMoreHistory() {
    bool isEmpty = chatItems.isEmpty;

    chatRepository
        .chatHistory(chatItems.isEmpty ? null : chatItems.last.id)
        .then((value) => chatItems.addAll(value))
        .whenComplete(() => refreshController.loadComplete())
        .whenComplete(() {
      if (isEmpty) {
        scrollToBottom();
      }
    });
  }

  void showStartSheet(BuildContext context) {
    if (!isOpenStart) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        showModalBottomSheet(
          context: context,
          isScrollControlled: true,
          barrierColor: ColorName.black55,
          backgroundColor: ColorName.transparent,
          builder: (BuildContext context) {
            return const ChatStartPage();
          },
        );
      });
      isOpenStart = true;
    }
  }

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

    chatItems.insert(
        0,
        ChatItem(
            id: chatItems.isEmpty ? 0 : chatItems.last.id + 1,
            conversationId:
                chatItems.isEmpty ? "" : chatItems.last.conversationId,
            role: "user",
            content: chatContent,
            createTime: DateTime.now().toString()));

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

    scrollToBottom();

    chatRepository.streamChat(chatContent).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;
          }
          progressingChatItem.append(delta.content ?? "");
        } 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 ?? "服务出错，请稍后再试";
      } else {
        progressingChatItem.error.value = "网络错误，请检查网络连接";
        debugPrint("error: $error");
        debugPrintStack();
      }
    });
  }

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