import 'package:chat/controllers/moment_controller.dart';
import 'package:chat/models/upload_model.dart';
import 'package:chat/routes/moments_routes.dart';
import 'package:chat/providers/moment_provider.dart';
import 'package:chat/utils/ui_tools.dart';
import 'package:chat/views/moments/publish/widgets/delete_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:tuple/tuple.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';

class PublishController extends GetxController {
  static PublishController get to => Get.find<PublishController>();
  static const fileMaxLength = 9;

  /// 发布"发现"的文件列表
  final publishFileList = <AssetEntity>[].obs;

  /// 已上传的文件获得的url
  ///
  /// [Tuple(hashCode, UploadModel)]
  final uploadedFileList = <Tuple2<int, UploadModel?>>[];

  /// preview页显示的下标
  final publistFileIndex = 0.obs;

  /// 发布的文本内容
  final publishContent = ''.obs;

  /// 退出确认
  Future<bool> exitConfirmation() async {
    if (publishFileList.isEmpty && publishContent.isEmpty) return true;
    final result = await Get.defaultDialog<bool?>(
      title: '确认',
      middleText: '退出后将不会保存内容',
      onConfirm: () {
        Get.back(result: true);
      },
    );
    return result == true;
  }

  Future<void> publish() async {
    FocusScope.of(Get.context!).requestFocus(FocusNode());
    EasyLoading.show(status: '上传中', maskType: EasyLoadingMaskType.black);
    final result = await uploadAllFile();
    if (!result) return;
    final res = await MomentProvider.publishMoment(
      description: publishContent.value,
      pictures: uploadedFileList.map((e) => e.item2!.url).toList(),
    );
    EasyLoading.dismiss();
    if (res != null) {
      UiTools.toast('动态发布成功');
      MomentController.to.refreshList();
      Get.back();
    }
  }

  Future<bool> uploadAllFile() async {
    try {
      for (var i = 0; i < publishFileList.length; i++) {
        final file = publishFileList[i];
        final exists = uploadedFileList.any(
          (e) => (e.item1 == file.hashCode && e.item2?.url != null),
        );
        if (!exists) {
          final res = await MomentProvider.uploadFile((await file.file)!.path);
          if (res == null) throw Exception('上传失败');
          for (var index = 0; index < uploadedFileList.length; index++) {
            final uploaded = uploadedFileList[index];
            if (uploaded.item1 == file.hashCode) {
              uploadedFileList[index] = uploaded.withItem2(res);
            }
          }
        }
      }
      return true;
    } catch (e) {
      UiTools.toast('上传失败');
      return false;
    }
  }

  Future<void> deleteImageOrVideo(int index) async {
    final result = await Get.dialog<bool?>(const PublishDeleteDialog());
    if (result == true) {
      removeFileByIndex(index);
    }
  }

  /// 选择文件并添加到[publishFileList]里
  Future<void> pickImageOrVideo() async {
    FocusScope.of(Get.context!).requestFocus(FocusNode());
    final result = await AssetPicker.pickAssets(
      Get.context!,
      pickerConfig: AssetPickerConfig(
        maxAssets: fileMaxLength - publishFileList.length,
        textDelegate: const AssetPickerTextDelegate(),
      ),
    );
    if (result == null) return;
    bool videoAlreadyExists =
        publishFileList.any((e) => e.type == AssetType.video);
    final list = result.where(
      (e) {
        if (e.type == AssetType.image) return true;
        if (videoAlreadyExists) return false;
        final authorized = e.videoDuration.inSeconds <= 30;
        if (authorized) videoAlreadyExists = true;
        return authorized;
      },
    ).toList();
    if (videoAlreadyExists && list.length != result.length) {
      UiTools.toast('最多能选择一个视频, 且视频时长不能超过30秒');
    } else if (list.length != result.length) {
      UiTools.toast('视频时长不能超过30秒');
    }
    // ignore: todo
    // TODO: 限制视频或者图片大小
    publishFileList.addAll(list);
    list.asMap().forEach((index, file) {
      uploadedFileList.add(Tuple2(file.hashCode, null));
    });
  }

  /// preview[publishFileList]里的文件
  void previewFiles(int index) {
    FocusScope.of(Get.context!).requestFocus(FocusNode());
    publistFileIndex.value = index;
    Get.toNamed(MomentsRoutes.publishPreview);
  }

  /// 按index删除file
  void removeFileByIndex(int index) {
    uploadedFileList.removeAt(index);
    publishFileList.removeAt(index);
    if (publishFileList.isEmpty &&
        Get.currentRoute == MomentsRoutes.publishPreview) Get.back();
    if (publistFileIndex.value >= publishFileList.length) {
      publistFileIndex.value = publishFileList.length - 1;
    }
  }

  /// 删除preview当前显示的file
  void removeFileByCurrentIndex() {
    removeFileByIndex(publistFileIndex.value);
  }
}
