import 'dart:async';

import 'package:cashier_reserve/common/base/ui_model.dart';
import 'package:cashier_reserve/common/channel/model/call_log_model.dart';
import 'package:cashier_reserve/common/channel/channel_manager.dart';
import 'package:cashier_reserve/common/channel/model/call_status_change_model.dart';
import 'package:cashier_reserve/common/manager/app_manager.dart';
import 'package:cashier_reserve/common/manager/event_manager.dart';
import 'package:cashier_reserve/common/print/print.dart';
import 'package:cashier_reserve/common/utils/utils.dart';
import 'package:cashier_reserve/data_model/reserve/reserve_log_model.dart';
import 'package:cashier_reserve/data_model/reserve/table_area_model.dart';
import 'package:cashier_reserve/data_model/reserve/table_model.dart';
import 'package:cashier_reserve/model/reserve_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:url_launcher/url_launcher.dart';

class ReserveViewModel extends BaseUIModel {
  Map<int, String> weekdayMap = {
    1: "星期一",
    2: "星期二",
    3: "星期三",
    4: "星期四",
    5: "星期五",
    6: "星期六",
    7: "星期日",
  };

  Map<int, String> dayInfoMap = {
    0: "今",
    1: "明",
    2: "后",
  };

  PageController pageController = PageController();
  AnimationController? _animationController;
  Animation<double>? _animationSizeFactor;

  Animation<double>? get animationSizeFactor => _animationSizeFactor;

  DateTime now = DateTime.now();

  int selectedDateIndex = 0;
  String selectedDate = "";
  String bookingType = "lunch";

  List<TableAreaModel?>? _tableAreaList;

  List<TableAreaModel?>? get tableAreaList => _tableAreaList;
  Map<num, TableAreaModel?> _tableAreaMap = {};

  List<TableModel?>? _tableList;

  List<TableModel?>? get tableList => _tableList;
  Map<String, List<TableModel?>> tableMap = {};

  List<CallLogModel?>? callLogs = [];

  Map<String, ReserveLogModel?>? _reserveLogMap;

  bool _isShowReserveInfoView = false;

  /// bookingGender 预订人性别 1: 男 2: 女
  int bookingGender = 1;

  /// bookingNumController 就餐人数
  TextEditingController bookingNumController = TextEditingController();

  /// bookingPhoneController 联系电话
  TextEditingController bookingPhoneController = TextEditingController();

  /// bookingNameController 预订人姓名
  TextEditingController bookingNameController = TextEditingController();

  /// bookingTypeController 预订类型
  TextEditingController bookingTypeController = TextEditingController();

  /// bookingTableNumController 预订台桌数量
  TextEditingController bookingTableNumController = TextEditingController();

  /// bookingStandardController 预定餐标
  TextEditingController bookingStandardController = TextEditingController();

  /// bookingRemarkController 备注
  TextEditingController bookingRemarkController = TextEditingController();

  /// bookingSelectedTime 预订时间
  String bookingSelectedTime = "";

  /// bookingFocus 重点关注
  bool bookingFocus = false;

  /// bookingSms 短信通知
  bool bookingSms = false;

  /// bookingStandardType 餐标类型
  String bookingStandardType = "table";

  String showTableName = "";

  TableModel? selectedTable;

  Timer? periodicTimer;

  ReserveViewModel() {
    selectedDate = "${now.year}-${now.month}-${now.day}";

    EventManager.addListener<GetCallLogEvent>(this, (event) {
      if (event.isSuccess) {
        if (!event.isSuccess) {
          return;
        }

        callLogs = event.callLogs;
        notifyListeners();

        loadUserReserveLog();
      }
    });

    loadCallLog();
    loadTableAreaList();
    loadAreaTableList(0);

    periodicTimer = Timer.periodic(const Duration(seconds: 30), (timer) {
      loadAreaTableList(0);
    });
  }

  @override
  void dispose() {
    pageController.dispose();
    bookingNumController.dispose();
    bookingPhoneController.dispose();
    bookingNameController.dispose();
    bookingTypeController.dispose();
    bookingTableNumController.dispose();
    bookingStandardController.dispose();
    bookingRemarkController.dispose();
    periodicTimer?.cancel();
    super.dispose();
  }

  reloadPageData() {
    loadCallLog();
    loadTableAreaList();
    loadAreaTableList(0);
    loadReserveSms();
  }

  void testCallIncoming() {
    CallStatusChangeModel model = CallStatusChangeModel(
      state: "Incoming",
      number: "123456789",
      name: "测试",
      region: "陕西省 西安市",
    );

    EventManager.postEvent(CallStatusChangeEvent(model: model));
  }

  void loadCallLog() {
    ChannelManager.getCallLog("getCallLog");
  }

  void loadUserReserveLog() async {
    List<String> phoneNos = [];
    for (var item in callLogs!) {
      phoneNos.add(item!.number ?? '');
    }
    _reserveLogMap = await ReserveModel.getUserReserveLog(phoneNos);

    notifyListeners();
  }

  void loadTableAreaList() async {
    final r = await ReserveModel.getShopTableAreaList();

    _tableAreaList = r;

    _tableAreaList ??= [];

    _tableAreaMap = {};
    for (var item in _tableAreaList!) {
      _tableAreaMap[item!.id!] = item;
    }

    _tableAreaList!.insert(0, TableAreaModel(id: 0, name: "全部"));

    notifyListeners();
  }

  void loadAreaTableList(int areaId) async {
    final r =
        await ReserveModel.getAreaTableList(areaId, selectedDate, bookingType);

    _tableList = r;

    _tableList ??= [];

    tableMap = {};
    tableMap["0"] = _tableList!;
    for (var item in _tableList!) {
      String areaId = item!.areaId.toString();
      if (tableMap[areaId] == null) {
        tableMap[areaId] = [];
      }
      tableMap[areaId]!.add(item);
    }

    notifyListeners();
  }

  loadReserveSms() async {
    AppManager.loadReserveSms();
  }

  void commitReserveInfo({bool sendSms = false}) async {
    if (!_checkReserveInfo()) {
      return;
    }

    Map<String, dynamic> params = {
      "shopTableId": selectedTable!.id,
      "bookingDate": selectedDate,
      "bookingType": bookingType,
      "dinerNum": bookingNumController.text,
      "phoneNumber": bookingPhoneController.text,
      "bookingPerson": bookingNameController.text,
      "gender": bookingGender,
      "bookingTime": '$selectedDate $bookingSelectedTime:00',
      "diningType": bookingTypeController.text,
      "focus": bookingFocus ? 1 : 0,
      "receiveMarketingSms": bookingSms ? 1 : 0,
      "bookingTableNum": bookingTableNumController.text,
      "diningStandardPrice": bookingStandardController.text,
      "diningStandardUnit": bookingStandardType,
      "remark": bookingRemarkController.text,
    };

    await ReserveModel.commitReserveInfo(params);

    Utils.toast("预定成功", context);
    hideReserveInfoView();
    loadAreaTableList(0);

    if (sendSms) {
      String smsContent = await AppManager.loadReserveSms();
      if (smsContent.isNotEmpty) {
        yjPrint("send sms: $smsContent, phone: ${bookingPhoneController.text}");

        goSendSms(phone: bookingPhoneController.text, message: smsContent);
      }
    }
  }

  goSendSms({required String phone, required String message}) async {
    final Uri smsUri = Uri(
      scheme: 'sms',
      path: phone,
      queryParameters: {
        'body': message,
      },
    );
    if (await canLaunchUrl(smsUri)) {
      await launchUrl(smsUri);
    } else {
      // 如果无法启动短信发送，可在此处添加相应的提示逻辑，比如打印错误信息等
      yjPrint('Could not launch SMS');
    }
  }

  void setSelectedDateIndex(int index) {
    selectedDateIndex = index;

    DateTime offsetDay = now.add(Duration(days: index ~/ 2));
    selectedDate = "${offsetDay.year}-${offsetDay.month}-${offsetDay.day}";
    bookingType = index % 2 == 0 ? "lunch" : "dinner";

    notifyListeners();

    loadAreaTableList(0);
  }

  void setAnimationController(
      AnimationController controller, Animation<double> sizeFactor) {
    _animationController = controller;
    _animationSizeFactor = sizeFactor;
  }

  ReserveLogModel? getReserveLogModel(String phone) {
    return _reserveLogMap?[phone];
  }

  showReserveInfoView() {
    _resetReserveData();
    _isShowReserveInfoView = true;
    _animationController?.forward();
    notifyListeners();
  }

  hideReserveInfoView() {
    _isShowReserveInfoView = false;
    _animationController?.reverse();
  }

  execCallLog(CallLogModel? callLog) {
    showReserveInfoView();
    bookingPhoneController.text = callLog?.number ?? "";
    bookingNameController.text = callLog?.name ?? "";
    notifyListeners();
  }

  updateBookingTime(int hour, int minute) {
    bookingSelectedTime =
        "${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}";
    notifyListeners();
  }

  updateBookingGender(int gender) {
    if (bookingGender == gender) {
      return;
    }
    bookingGender = gender;
    notifyListeners();
  }

  updateBookingAttr(String key, bool val) {
    if (key == "focus") {
      bookingFocus = val;
    } else if (key == "sms") {
      bookingSms = val;
    }
    notifyListeners();
  }

  updateBookingStandard(String standard) {
    bookingStandardType = standard;
    notifyListeners();
  }

  clickTable(TableModel table) {
    if (_isShowReserveInfoView) {
      if (table.bookingInfo != null) {
        Utils.toast("当前台桌已预定", context);
        return;
      }
      selectedTable = table;
      TableAreaModel? area = _tableAreaMap[table.areaId!];
      showTableName = "${area?.name ?? ""} - ${table.name}";
      notifyListeners();

      return;
    }

    if (table.bookingInfo == null) {
      return;
    }

    _changeReserveStatus(table);
  }

  _resetReserveData() {
    bookingGender = 1;
    bookingNumController.text = "";
    bookingPhoneController.text = "";
    bookingNameController.text = "";
    bookingTypeController.text = "";
    bookingTableNumController.text = "";
    bookingStandardController.text = "";
    bookingRemarkController.text = "";
    bookingSelectedTime = "";
    bookingFocus = false;
    bookingSms = false;
    bookingStandardType = "table";
    selectedTable = null;
    showTableName = "";
  }

  _changeReserveStatus(TableModel table) async {
    var result = await showCupertinoModalPopup(
        context: context!,
        builder: (context) {
          return CupertinoActionSheet(
            title: const Text('预定信息'),
            actions: <Widget>[
              CupertinoActionSheetAction(
                onPressed: () {
                  Navigator.of(context).pop('arrive');
                },
                isDefaultAction: true,
                child: const Text('到店'),
              ),
              CupertinoActionSheetAction(
                child: const Text('取消预定'),
                onPressed: () {
                  Navigator.of(context).pop('cancelBooking');
                },
                // isDestructiveAction: true,
              ),
            ],
            cancelButton: CupertinoActionSheetAction(
              child: const Text('取消'),
              onPressed: () {
                Navigator.of(context).pop('cancel');
              },
            ),
          );
        });
    yjPrint('$result');

    if (result == 'arrive') {
      await ReserveModel.updateReserveStatus(table.bookingInfo?.id ?? 0, 10);
      Utils.toast("到店成功", context);
      loadAreaTableList(0);
    } else if (result == 'cancelBooking') {
      ReserveModel.updateReserveStatus(table.bookingInfo?.id ?? 0, -1);
      Utils.toast("取消成功", context);
      loadAreaTableList(0);
    }
  }

  bool _checkReserveInfo() {
    if (selectedTable == null) {
      Utils.toast("请选择台桌", context);
      return false;
    }

    if (bookingNumController.text.isEmpty) {
      Utils.toast("请输入就餐人数", context);
      return false;
    }

    if (bookingPhoneController.text.isEmpty) {
      Utils.toast("请输入联系电话", context);
      return false;
    }

    if (bookingNameController.text.isEmpty) {
      Utils.toast("请输入预订人姓名", context);
      return false;
    }

    if (bookingSelectedTime.isEmpty) {
      Utils.toast("请选择预订时间", context);
      return false;
    }

    if (bookingTypeController.text.isEmpty) {
      Utils.toast("请输入预订类型", context);
      return false;
    }

    return true;
  }

  String getCurrentDate() {
    return "${now.year}/${now.month}/${now.day}";
  }

  String getOffsetDay(int offset) {
    DateTime offsetDay = now.add(Duration(days: offset));
    return "${dayInfoMap[offset]}/${offsetDay.day}";
  }

  String getOffsetWeekday(int offset) {
    DateTime offsetDay = now.add(Duration(days: offset));
    return weekdayMap[offsetDay.weekday] ?? "";
  }
}
