/*
 * @Author: WuXiangNan
 * @Date: 2021-02-22 14:15:47
 * @LastEditTime : 2023-05-25 15:46:36
 * @LastEditors  : WuWei
 * @Description: 
 */

import 'dart:async';
import 'package:attendance_package/src/models/enum.dart';
import 'package:attendance_package/src/models/response_model/clock_status/rules_model.dart';
import 'package:geolocator/geolocator.dart';
import 'package:intl/intl.dart';
// import 'package:wisdom_cli/new/widgets/uploader.dart';
import '../public/location.dart';
import 'package:flutter/material.dart';
import '../models/location_info_model.dart';
import 'package:wisdom_cli/wisdom_cli.dart';
import 'package:app_package/app_package.dart';
import '../service/impl/attendance_service_impl.dart';
import 'package:attendance_package/src/assets.gen.dart';
import 'package:attendance_package/src/models/clock_model.dart';
import '../models/response_model/clock_status/clock_status_data_model.dart';
import '../models/response_model/clock_status/current_clock_status_vos_model.dart';
import 'package:attendance_package/src/models/response_model/clock_status/location_clock_model.dart';
import 'dart:math' as math;

const double X_PI = math.pi * 3000.0 / 180.0;
const double OFFSET = 0.00669342162296594323;
const double AXIS = 6378245.0;

enum _PositionItemType {
  log,
  position,
}

// class _TransformTmp {
//   double x, y;

//   _TransformTmp(this.x, this.y);
// }

class _PositionItem {
  _PositionItem(this.type, this.displayValue);

  final _PositionItemType type;
  final String displayValue;
}

// ///百度坐标
class BdLatLng {
  double latitude;
  double longitude;
  BdLatLng({required this.latitude, required this.longitude});
}

class AttendanceStore with ChangeNotifier {
  final BuildContext context;
  late Map args;
  AttendanceStore(this.context) {
    args =
        ModalRoute.of(context)!.settings.arguments as Map<dynamic, dynamic>? ??
            {};
  }

  var phoneInfo;

  List<CurrentClockStatusVosModel>? clockTimeLineList;

  String? clockRangeStatus;

  final scorllViewKey = GlobalKey<WisScrollViewState>();
  final clockInKey = GlobalKey();

  LocationStore get locationStore =>
      Provider.of<LocationStore>(context, listen: false);
  final authGlobalStore = GetIt.I.get<AuthGlobalStore>();
  //当前员工的信息
  EmployeesInfoModel? get userInfo => authGlobalStore.info;

  // 员工的定位信息
  LocationInfo? get location => locationStore.myLocation;

  late Position positionInTime;

  ClockModel clockModel = ClockModel();

  ClockStatusDataModel? clockStatusData;

  List<LocationClockModel>? locationClockList;

  String? groupIdentification;

  ScrollController scrollController = ScrollController();

  int _currentIndex = 0;
  get currentIndex => _currentIndex;

  List _legWorkNeed = [];

  String shiftType = '';
  Timer? timer;
  // StreamSubscription<Map<String, Object>>? _locationListener;

  String? address;

  final GeolocatorPlatform _geolocatorPlatform = GeolocatorPlatform.instance;
  final List<_PositionItem> _positionItems = <_PositionItem>[];
  StreamSubscription<Position>? _positionStreamSubscription;
  StreamSubscription<ServiceStatus>? _serviceStatusStreamSubscription;
  bool positionStreamStarted = false;

  Future<bool> requestLocationPermission() async {
    bool locationServiceEnabled = true;
    //获取当前的权限
    LocationPermission status = await Geolocator.checkPermission();
    switch (status) {
      case LocationPermission.denied:
        locationServiceEnabled = false;
        break;
      case LocationPermission.deniedForever:
        locationServiceEnabled = false;
        break;
      case LocationPermission.unableToDetermine:
        locationServiceEnabled = false;
        break;
      default:
        break;
    }
    print("GeoUtil - isReady - $locationServiceEnabled");
    return locationServiceEnabled;
  }

  Future<bool> getLocationPermission() async {
    bool locationServiceEnabled = true;
    //获取当前的权限
    LocationPermission status = await Geolocator.requestPermission();
    switch (status) {
      case LocationPermission.denied:
        locationServiceEnabled = false;
        break;
      case LocationPermission.deniedForever:
        locationServiceEnabled = false;
        break;
      case LocationPermission.unableToDetermine:
        locationServiceEnabled = false;
        break;
      default:
        break;
    }
    print("GeoUtil - isReady - $locationServiceEnabled");
    return locationServiceEnabled;
  }

  Future<void>? onInit() async {
    // 初始化定位
    // final hasPermission = await requestLocationPermission();
    // if (hasPermission != true) {
    //   final isHas = await getLocationPermission();
    //   print(isHas);
    //   if (isHas) {
    //     // getStream();
    //     getPostion();
    //   } else {
    //     /// 再次请求一遍
    //     final isHas = await getLocationPermission();
    //     if (isHas) {
    //       // getStream();
    //       getPostion();
    //     } else {
    //       final opened = await _geolocatorPlatform.openLocationSettings();
    //       if (opened == true) {
    //         // getStream();
    //         getPostion();
    //       }
    //     }
    //   }
    // } else {
    //   print('kkkkkkkkkkkkkkkkkkkkkkkkkkkkk');
    //   // getStream();
    //   getPostion();
    // }
     // 查询打卡初始数据
      onPostClockStatus();
      notifyListeners();
  }

  void getPostion() async {
    positionInTime = await _geolocatorPlatform.getCurrentPosition();
    notifyListeners();
  }

  void destory() {
    ///移除定位监听
    if (_positionStreamSubscription != null) {
      _positionStreamSubscription!.cancel();
      _positionStreamSubscription = null;
      if (timer != null) timer!.cancel();
    }
    if (reflashTimer != null) {
      reflashTimer!.cancel();
    }
  }

  void getStream() {
    _positionStreamSubscription = Geolocator.getPositionStream(
        locationSettings: LocationSettings(
      accuracy: LocationAccuracy.high,
      distanceFilter: 10,
    )).listen((position) {
      // 更新位置
      positionInTime = position;
     
    });
  }

  // void _toggleServiceStatusStream() {
  //   if (_serviceStatusStreamSubscription == null) {
  //     final serviceStatusStream = _geolocatorPlatform.getServiceStatusStream();
  //     _serviceStatusStreamSubscription =
  //         serviceStatusStream.handleError((error) {
  //       _serviceStatusStreamSubscription?.cancel();
  //       _serviceStatusStreamSubscription = null;
  //     }).listen((serviceStatus) {
  //       String serviceStatusValue;
  //       if (serviceStatus == ServiceStatus.enabled) {
  //         if (positionStreamStarted) {
  //           _toggleListening();
  //         }
  //         serviceStatusValue = 'enabled';
  //       } else {
  //         if (_positionStreamSubscription != null) {
  //           _positionStreamSubscription?.cancel();
  //           _positionStreamSubscription = null;
  //           _updatePositionList(
  //               _PositionItemType.log, 'Position Stream has been canceled');
  //         }
  //         serviceStatusValue = 'disabled';
  //       }
  //       _updatePositionList(
  //         _PositionItemType.log,
  //         'Location service has been $serviceStatusValue',
  //       );
  //     });
  //   }
  // }

  void _updatePositionList(_PositionItemType type, String displayValue) {
    _positionItems.add(_PositionItem(type, displayValue));
  }

  // void _toggleListening() {
  //   if (_positionStreamSubscription == null) {
  //     final positionStream = _geolocatorPlatform.getPositionStream();
  //     _positionStreamSubscription = positionStream.handleError((error) {
  //       _positionStreamSubscription?.cancel();
  //       _positionStreamSubscription = null;
  //     }).listen((position) => _updatePositionList(
  //           _PositionItemType.position,
  //           position.toString(),
  //         ));
  //     _positionStreamSubscription?.pause();
  //   }

  //   if (_positionStreamSubscription == null) {
  //     return;
  //   }

  //   String statusDisplayValue;
  //   if (_positionStreamSubscription!.isPaused) {
  //     _positionStreamSubscription!.resume();
  //     statusDisplayValue = 'resumed';
  //   } else {
  //     _positionStreamSubscription!.pause();
  //     statusDisplayValue = 'paused';
  //   }

  //   _updatePositionList(
  //     _PositionItemType.log,
  //     'Listening for position updates $statusDisplayValue',
  //   );
  // }

  // 考勤打卡
  Future _onPostClock() async {
    WLoadingUtil.show();
    var photo = await _upLoad();
    // Position pos = await _geolocatorPlatform.getCurrentPosition();
    // print(pos);
    final res = await AttendanceServiceImpl().postAttendanceClock({
      'employeeId': userInfo!.id,
      'companyId': userInfo!.companyId,
      'clockWay': '0',
      /// 暂时写死
      'longitude': 110.34077761842357,
      'latitude': 20.06438607477896,
      // 自行判断打卡状态
      // 'clockStatus': clockRangeStatus, 
      'clockStatus': 'normal', 
      'remark': clockModel.remark,
      'photo': photo,
      'shiftId': '',
      // 'location': clockRangeStatus == 'legwork' ? locationStore.addr : address,
      'location': '任意打卡',
      'phoneId': phoneInfo['id'],
      'model': phoneInfo['model'],
    });
    if (res == true)
      // 等待两秒查询打卡结果
      Timer(Duration(seconds: 2), () {
        onPostClockStatus(reflash: true);
      });
    else
      WLoadingUtil.hide();
  }

  // 考勤打卡状态
  Future<void> onPostClockStatus({bool? reflash}) async {
    // phoneInfo = await AppDeviceInfo.getDeviceId();
    final res = await AttendanceServiceImpl().postClockStatus({
      'employeeId': userInfo!.id,
      'companyId': userInfo!.companyId,
      'clockWay': '0',
      // 'phoneId': phoneInfo['id'],
      // 'model': phoneInfo['model'],
    });
    WLoadingUtil.hide();

    clockStatusData = res.data;
    // 自动刷新状态
    getClockStatus();
    notifyListeners();
    // 打卡时间线
    clockTimeLineList = clockStatusData!.currentClockStatusVos;
    // 打卡地点
    locationClockList = clockStatusData!.clockWayContent?.locationClock;

    // 考勤组
    groupIdentification = clockStatusData!.groupIdentification;
    notifyListeners();

    // 打卡属于外勤还是正常范围内
    // clockRangeStatus = await isNormalOrLegwork();
    notifyListeners();

    var legWorkSetting = clockStatusData!.legWorkSetting!.split(',');
    // 将外勤打卡设置与枚举一一映射 避免魔鬼数字
    for (var i in legWorkSetting) {
      _legWorkNeed.add(LegWorkSetting.values[int.parse(i)].toString());
    }

    shiftType = ShiftType.values[clockStatusData!.shiftType!].toString();
    if (clockStatusData?.currentClockStatusVos?.length == 0 &&
        shiftType == '') {
      WToastUtil.show('班次信息为空，请联系管理员处理。', location: WToastLoction.center);
    }

    // 滚动到打卡位置
    scrollToClock();

    // 寻找当前打卡节点位置
    _findCurrentIndex();

    // 是否是打卡结束的查询请求
    if (reflash ?? false) {
      _showClockResult();
    }
  }

  // 判断打卡类型为外勤还是正常
  Future<String> isNormalOrLegwork() async {
    Map map = locationStore.onGetMinDistance(locationClockList!);
    int minDistanceIndex = map['minDistanceIndex'];
    double minDistance = map['minDistance'];
    if (minDistance < locationClockList![minDistanceIndex].scope!.toInt()) {
      address = locationClockList![minDistanceIndex].locateName;
      return 'normal';
    } else {
      address = locationStore.addr;
      return 'legwork';
    }
  }

  Future setClockRangeStatus() async {
    // clockRangeStatus = await isNormalOrLegwork();
    // notifyListeners();
  }

  _showClockResult() {
    bool flag = false;

    if (clockTimeLineList![_currentIndex].clockTime != null) {
      flag = true;
    }

    WLoadingUtil.hide();
    if (flag) {
      showDialog(
        context: context,
        builder: (context) {
          return Wisdom(
              child: WisDialog(
            title: Text(''),
            insetPadding: EdgeInsets.symmetric(vertical: 0),
            content: Wisdom.column(
              height: ClockType
                          .values[clockTimeLineList![_currentIndex].clockType!]
                          .toString() ==
                      'ClockType.AFTERWORK'
                  ? 180.pt
                  : 140.pt,
              width: 200.pt,
              color: Colors.white,
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                Image(
                  image: AssetList.$chg_png_image,
                  height: 49.pt,
                ),
                Wisdom(
                  margin: EdgeInsets.only(top: 20.pt),
                  child: WisText(
                    '打卡成功',
                    bold: true,
                    color: Colors.black,
                    size: 18.pt,
                  ),
                ),
                // 如果是下班打卡，显示总上班时长
                if (ClockType
                        .values[clockTimeLineList![_currentIndex].clockType!]
                        .toString() ==
                    'ClockType.AFTERWORK')
                  Wisdom(
                    margin: EdgeInsets.only(top: 10.pt),
                    child: WisText(
                        '共上班${computedWorkTime(clockStatusData!.currentClockStatusVos!)}'),
                  ),
              ],
            ),
          ));
        },
      );
    } else {
      WToastUtil.show('打卡失败', location: WToastLoction.center);
    }
  }

  _findCurrentIndex() {
    // 自由工时当天无打卡情况特殊处理
    if (shiftType == 'ShiftType.FREE_TIME' && clockTimeLineList!.length > 0) {
      _currentIndex = clockTimeLineList!.length - 1;
      return;
    }

    // 排班制当天无排班特殊处理
    if (shiftType == 'ShiftType.SCHEDULING' &&
        clockTimeLineList!.length > 0 &&
        clockStatusData!.workDay == false) {
      _currentIndex = clockTimeLineList!.length - 1;
      return;
    }

    // 寻找当前打卡节点位置
    for (var i = 1; i < clockTimeLineList!.length; i++) {
      if (clockTimeLineList![i].current == true) {
        if (i != clockTimeLineList!.length - 1 ||
            (i == clockTimeLineList!.length - 1 &&
                clockTimeLineList![i].clockTime == null))
          // 获取上一个结果
          _currentIndex = i - 1;
        else {
          _currentIndex = i;
        }
        return;
      }
    }
  }

  void scrollToClock() {
    // 跳到打卡位置
    WidgetsBinding.instance.addPostFrameCallback((duration) {
      if (clockInKey.currentContext?.findRenderObject() != null) {
        RenderBox box =
            clockInKey.currentContext?.findRenderObject() as RenderBox;
        if (MediaQuery.of(context).size.height <
            (box.localToGlobal(Offset.zero).dy + box.size.height))
          scrollController.animateTo(box.localToGlobal(Offset.zero).dy,
              duration: Duration(milliseconds: 2000), curve: Curves.ease);
      }
    });
  }

  // 打卡
  Future clockIn() async {
    // 未到时间不可打卡
    // if (clockStatusData!.clockStatusCode == 'noWorkTime') {
    //   return;
    // }

    // // 无定位信息
    // if (location!.latitude == null) {
    //   locationStore.showErrorLocationDialog();
    //   return;
    // }

    // // 判断是否外勤
    // if (clockRangeStatus == 'legwork') {
    //   _showLegWorkDialog();
    // } else {
    _onPostClock();
    // }
  }

  final FocusNode focusNode = FocusNode();
  // _showLegWorkDialog() {
  //   clockModel.remark = null;

  //   return WBottomModalUtil.show(
  //     context,
  //     title: Text('请填写外勤说明'),
  //     bodyConstraints: BoxConstraints(
  //       maxHeight: 370,
  //       minHeight: 250,
  //     ),
  //     body: Wisdom.column(
  //       onTap: () {
  //         focusNode.unfocus();
  //       },
  //       crossAxisAlignment: CrossAxisAlignment.start,
  //       children: [
  //         Wisdom(
  //           padding: EdgeInsets.symmetric(horizontal: 15.pt),
  //           child: WFormTile(
  //             required:
  //                 _legWorkNeed.indexOf('LegWorkSetting.NEED_REASON') != -1,
  //             leading: Text(
  //               '外勤说明',
  //               style: TextStyle(fontSize: 15.pt, color: Color(0xff222222)),
  //             ),
  //           ),
  //         ),
  //         Wisdom(
  //           margin: EdgeInsets.symmetric(horizontal: 15.pt),
  //           child: TextField(
  //             focusNode: focusNode,
  //             onChanged: (v) {
  //               clockModel.remark = v;
  //             },
  //             scrollPadding: EdgeInsets.zero,
  //             decoration: InputDecoration(
  //               fillColor: Colors.white,
  //               contentPadding: EdgeInsets.fromLTRB(9.pt, 0, 9.pt, 0),
  //               hintText: '请输入外勤说明',
  //             ),
  //             minLines: 5,
  //             maxLines: 5,
  //             maxLength: 64,
  //           ),
  //         ),
  //         Wisdom(
  //             margin: EdgeInsets.symmetric(
  //               vertical: 10.pt,
  //             ),
  //             child: Divider(
  //               height: 0.5,
  //             )),
  //         Wisdom(
  //           margin: EdgeInsets.symmetric(horizontal: 15.pt),
  //           child: WFormTile(
  //             required: _legWorkNeed.indexOf('LegWorkSetting.NEED_PHOTO') != -1,
  //             leading: WisText(
  //               '外勤拍照',
  //             ),
  //           ),
  //         ),
  //         WUpLoader.wrap(
  //           padding: EdgeInsets.fromLTRB(25.pt, 0, 25.pt, 10.pt),
  //           onChanged: (files) => _filesChanged(files),
  //           builder: (context, index) {
  //             return WUpLoaderChild.image(index: index);
  //           },
  //           selector: WUpLoaderChild.imagePicker(
  //             maxCount: 3,
  //             child: Wisdom.column(
  //               mainAxisAlignment: MainAxisAlignment.start,
  //               children: [
  //                 Image(
  //                   image: AssetList.$sctp_png_image,
  //                 ),
  //               ],
  //             ),
  //           ),
  //         ),
  //         WButton(
  //           margin: EdgeInsets.fromLTRB(15.pt, 0, 15.pt, 0.pt),
  //           height: 44.pt,
  //           minWidth: MediaQuery.of(context).size.width - 30.pt,
  //           onPressed: () => {
  //             // update2.2
  //             if (_legWorkNeed.indexOf('LegWorkSetting.NEED_REASON') != -1 &&
  //                 clockModel.remark == null)
  //               {
  //                 WToastUtil.show('外勤说明不为空', location: WToastLoction.center),
  //               }
  //             else if (_legWorkNeed.indexOf('LegWorkSetting.NEED_PHOTO') !=
  //                     -1 &&
  //                 files.length == 0)
  //               {
  //                 WToastUtil.show('外勤拍照不为空', location: WToastLoction.center),
  //               }
  //             else
  //               {Navigator.pop(context), _onPostClock()}
  //           },
  //           child: Text(
  //             '确定',
  //             style: TextStyle(fontSize: 17.pt),
  //           ),
  //         ),
  //       ],
  //     ),
  //   );
  // }

  ///图片选择
  List<FileEntity> files = [];
  // _filesChanged(List<FileEntity> _files) {
  //   files = _files;
  //   notifyListeners();
  // }

  Map<String, String> uploadeds = {}; //已上传(缓存)
  // 上传外勤照片
  Future<String> _upLoad() async {
    ///未上传的
    final waitUpLoads =
        files.where((e) => uploadeds[e.file!.path] == null).toList();

    final futures =
        waitUpLoads.map((e) => GlobalApi.postUploadImage(e.file!)).toList();

    final res = await Future.wait(futures);

    for (var i = 0; i < waitUpLoads.length; i++) {
      final path = waitUpLoads[i].file!.path;
      if (res[i]!.data != null) {
        uploadeds[path] = res[i]!.data!;
      }
    }
    List list = files.map((e) => uploadeds[e.file!.path]).toList();
    String photo = list.join(',');
    return photo;
  }

  // 日期格式转换
  timeFormat(String? value) {
    var date = value ?? '';

    if (date == '') {
      return null;
    }
    DateTime dateTime = DateTime.parse(date);
    DateFormat outputFormat = DateFormat("HH:mm");
    return outputFormat.format(dateTime);
  }

  // 计算有效出勤工时
  String computedWorkTime(List<CurrentClockStatusVosModel> clockInfos) {
    var timeTemp = 0;

    for (int i = 1; i < clockInfos.length; i = i + 2) {
      if (clockInfos[i].clockResult != 4 &&
          clockInfos[i].clockTime != null &&
          clockInfos[i - 1].clockTime != null)
        timeTemp = timeTemp +
            (DateTime.parse(clockInfos[i].clockTime!).millisecondsSinceEpoch -
                DateTime.parse(clockInfos[i - 1].clockTime!)
                    .millisecondsSinceEpoch);
    }
    return _durationTransform(timeTemp);
  }

  //时间转换 将豪秒转换为小时分钟
  String _durationTransform(int milliseconds) {
    var d = Duration(milliseconds: milliseconds);
    List<String> parts = d.toString().split(':');
    return '${parts[0]}小时${parts[1]}分钟';
  }

  String? status;
  Timer? reflashTimer;
  String? clockStatusCode;
  static late Function staticNotifyListeners;
  // 当前打卡状态
  getClockStatus() {
    staticNotifyListeners = notifyListeners;
    reflashTimer = Timer.periodic(Duration(seconds: 1), (timer) {
      var now = DateTime.now();

      status = null;
      late int index;

      for (int i = 0; i < clockTimeLineList!.length; i++) {
        if (clockTimeLineList![i].current == true) {
          index = i;
        }
      }
      staticNotifyListeners();
      for (RulesModel rule in clockStatusData!.rules!) {
        if (rule.type == 'late' &&
            (now.millisecondsSinceEpoch -
                    DateTime.parse(clockTimeLineList![index].shouldClockTime!)
                        .millisecondsSinceEpoch >
                int.parse(rule.time!) * 60 * 1000) &&
            clockTimeLineList![index].clockType == 0) {
          status = '迟到打卡';
          staticNotifyListeners();
        }
        if (rule.type == 'serious' &&
            now.millisecondsSinceEpoch -
                    DateTime.parse(clockTimeLineList![index].shouldClockTime!)
                        .millisecondsSinceEpoch >
                int.parse(rule.time!) * 60 * 1000 &&
            clockTimeLineList![index].clockType == 0) {
          status = '严重迟到打卡';
          staticNotifyListeners();
        }

        if (rule.type == 'serious' &&
            DateTime.parse(clockTimeLineList![index].shouldClockTime!)
                        .millisecondsSinceEpoch -
                    now.millisecondsSinceEpoch >
                int.parse(rule.time!) * 60 * 1000 &&
            clockTimeLineList![index].clockType == 1) {
          status = '严重早退打卡';
          staticNotifyListeners();
        }

        if (rule.type == 'leaveEarly' &&
            (DateTime.parse(clockTimeLineList![index].shouldClockTime!)
                        .millisecondsSinceEpoch -
                    now.millisecondsSinceEpoch >
                int.parse(rule.time!) * 60 * 1000) &&
            clockTimeLineList![index].clockType == 1) {
          status = '早退打卡';
          staticNotifyListeners();
        }
      }
    });
  }
}
