import 'dart:async';
import 'dart:io';

import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:geolocation/models/position.dart';
import 'package:get/get.dart';

import '../../../../common/api/index.dart';
import '../../../../common/models/index.dart';
import '../../../../common/routers/index.dart';
import '../../../../common/services/index.dart';
import '../../../../common/utils/index.dart';
import '../../../../common/extension/index.dart';
import '../../../../common/widgets/index.dart';
import 'index.dart';

class MainController extends GetxController with WidgetsBindingObserver {
  MainController();

  final state = MainState();

  final pageViewController = PageController();

  // 外勤打卡，需要输入说明
  final TextEditingController outsideCheckInDescInputController =
      TextEditingController();

  // 定时器
  Timer? _timer;

  /// geolocator 定位
  GeolocatorHelper? _geoHelper;

  /// 当前定位信息
  GeoPosition? myPosition;

  // 工作地点
  List<WorkPlaceList> workplaceList = [];
  WorkPlaceList? nearLeastWorkplace; // 范围内的打卡地点
  // BaiduLocation? myLocation; // 当前定位信息
  AttendanceV2Record? currentCheckItem; // 当前打卡对象
  bool allowFieldWork = false; // 是否允许外勤打卡
  bool requiredFieldWorkRemarks = false; // 描述是否必填

  /// 在 widget 内存中分配后立即调用。
  @override
  void onInit() {
    WidgetsBinding.instance.addObserver(this);
    super.onInit();
  }

  /// 在 onInit() 之后调用 1 帧。这是进入的理想场所
  @override
  void onReady() {
    state.title = Get.parameters['displayName'] ?? "app_name_attendance".tr;

    /// 间隔1秒
    _timer = Timer.periodic(const Duration(milliseconds: 1000), (timer) {
      ///定时任务
      updateTimePerSecond();
    });
    // 初始化定位程序
    _geoHelper = GeolocatorHelper(callback: (position) {
      myPosition = position;
      _calNearestWorkplace();
    });
    _geoHelper?.startLocation();

    // 初始化数据
    _loadPreCheckInData();
    _loadMyStatisticData();
    super.onReady();
  }

  /// 在 [onDelete] 方法之前调用。
  @override
  void onClose() {
    // 取消定时器
    _timer?.cancel();
    // _helper?.stopLocation();
    _geoHelper?.stopLocation();
    WidgetsBinding.instance.removeObserver(this);
    super.onClose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) async {
    OLogger.d("attendance LifecycleState ==========  $state");
    if (state == AppLifecycleState.resumed) {
      OLogger.d('重新进入 刷新数据！');
      _loadPreCheckInData();
    }
  }

  /// 统计
  _loadMyStatisticData() async {
    final now = DateTime.now();
    final startDate = now.monthFirstDate();
    final endDate = now.monthLastDate();
    state.currentYear = '${now.year}';
    state.currentMonth = 'attendance_statistic_month'.trArgs(['${now.month}']);
    final result = await AttendanceAssembleControlService.to
        .myStatistic(startDate.ymd(), endDate.ymd());
    if (result != null) {
      state.myStatistic.value = result;
    }
  }

  /// 进入异常数据页面
  void clickOpenExceptionPage() {
    OLogger.d('点击了 异常数据页面');
    Get.toNamed(O2OARoutes.appAttendanceExceptionDataPage);
  }

  ///
  /// 获取打卡初始化数据
  ///
  void _loadPreCheckInData() async {
    var data = await AttendanceAssembleControlService.to.loadPreCheckInData();
    if (data != null) {
      bool needCheck = data.canCheckIn ?? false; //今天是否还需要打卡
      allowFieldWork = data.allowFieldWork ?? false;
      requiredFieldWorkRemarks = data.requiredFieldWorkRemarks ?? false;
      // 打卡记录
      var checkItemList = data.checkItemList ?? [];
      // 是否最后一条已经打卡过的数据
      currentCheckItem = checkItemList
          .firstWhereOrNull((element) => element.checkInResult == 'PreCheckIn');
      if (currentCheckItem != null) {
        needCheck = true;
      } else {
        needCheck = false;
      }
      for (var i = 0; i < checkItemList.length; i++) {
        var item = checkItemList[i];
        if (item.checkInResult != 'PreCheckIn') {
          if (i == checkItemList.length - 1) {
            item.isLastRecord = true;
            checkItemList[i] = item;
          } else {
            var nextItem = checkItemList[i + 1];
            if (nextItem.checkInResult == 'PreCheckIn') {
              item.isLastRecord = true;
              checkItemList[i] = item;
            }
          }
        }
      }
      state.todayNeedCheck = needCheck;
      state.checkItemList.clear();
      state.checkItemList.addAll(checkItemList);

      // 工作场所
      _listAllAttendanceWorkPlace(data.workPlaceList);
    } else {
      Loading.showError('attendance_request_error'.tr);
      Get.back();
    }
  }

  void _listAllAttendanceWorkPlace(List<WorkPlaceList>? list) {
    if (list != null && list.isNotEmpty) {
      workplaceList.clear();
      workplaceList.addAll(list);
      // 计算最近的打卡地点
      _calNearestWorkplace();
    }
  }

  ///
  /// 提交打卡
  ///
  void _postCheckIn(
      String latitude, String longitude, String addrStr, String checkType,
      {String workPlaceId = '',
      String signDesc = '',
      String id = '',
      bool isExternal = false,
      String workAddress = ''}) async {
    if (isExternal) {
      // 外勤打开
      if (signDesc.isEmpty) {
        Loading.toast('attendance_outside_need_desc'.tr);
        return;
      }
    }
    Loading.show();
    var post = CheckPost(
        recordId: id,
        checkInType: checkType,
        workPlaceId: workPlaceId,
        fieldWork: isExternal,
        signDescription: signDesc,
        latitude: latitude,
        longitude: longitude,
        recordAddress: addrStr,
        sourceType: 'USER_CHECK');
    var deviceType = SharedPreferenceService.to
        .getString(SharedPreferenceService.currentDeviceTypeKey);

    final checkScript =
        await _externalCheck(id, deviceType, checkType, isExternal);
    if (!checkScript.check) {
      Loading.dismiss();
      OLogger.e('打卡检查脚本失败, ${checkScript.deviceId} ${checkScript.message}');
      var message = 'attendance_checkin_external_check_error'.tr;
      if (checkScript.message != null && checkScript.message!.isNotEmpty) {
        message = checkScript.message!;
      }
      Loading.toast(message);
      return;
    }
    post.sourceDevice = checkScript.deviceId;

    var iddata = await AttendanceAssembleControlService.to.checkInPostV2(post);
    if (iddata != null) {
      Loading.dismiss();
      _loadPreCheckInData();
    }
  }

  Future<String> _getDeviceId() async {
    String deviceId = SharedPreferenceService.to
        .getString(SharedPreferenceService.attendanceDeviceIdSpKey);
    if (deviceId.isNotEmpty && deviceId != 'unknown') {
      OLogger.d('获取到本地存储的设备 id：$deviceId');
      return deviceId;
    }
    if (Platform.isIOS) {
      var iosDeviceInfo = await deviceInfoPlugin.iosInfo;
      deviceId = iosDeviceInfo.identifierForVendor ?? 'unknown'; // unique ID on iOS
    } else if(Platform.isAndroid) {
      var androidDeviceInfo = await deviceInfoPlugin.androidInfo;
      deviceId = androidDeviceInfo.id; // unique ID on Android
    } else {
      deviceId = 'unknown';
    }
    SharedPreferenceService.to.putString(SharedPreferenceService.attendanceDeviceIdSpKey, deviceId);
    OLogger.d('获取到设备 id：$deviceId');
    return deviceId;
  }

  /// 外部脚本 检查是否能打卡
  /// 需要在 appstyle 配置文件 【 extendParam 】中 配置 attendanceCheckScript字段，内容是invoke脚本名称
  Future<({bool check, String deviceId, String? message})> _externalCheck(
      String recordId,
      String deviceType,
      String checkInType,
      bool fieldWork) async {
    var deviceId = await _getDeviceId();
    if (deviceId.isEmpty) {
      OLogger.e('没有获取到设备 id！');
    }
    deviceId = '${deviceType}_$deviceId';
    final script =
        ProgramCenterService.to.extendParam()['attendanceCheckScript'];
    if (script == null || script is! String) {
      OLogger.i('没有打卡检查脚本！');
      return (check: true, deviceId: deviceId, message: null);
    }
    final body = {
      "recordId": recordId,
      "checkInType": checkInType,
      "fieldWork": fieldWork,
      "person": O2ApiManager.instance.me().distinguishedName,
      "device": deviceId
    };
    final result = await ProgramCenterService.to.executeScript(script, body);
    if (result != null) {
      OLogger.d('打卡检查脚本结果：$result');
      final s = result['result'];
      final message = (result['message'] != null && result['message'] is String)
          ? (result['message'] as String)
          : '';
      if (s != null && s is bool && s == false) {
        return (check: false, deviceId: deviceId, message: message);
      }
    }
    return (check: true, deviceId: deviceId, message: null);
  }

  ///
  /// 查找最近的打卡地点
  ///
  void _calNearestWorkplace() async {
    if (myPosition == null) {
      OLogger.e('还没有定位成功！');
      return;
    }
    state.currentAddress = 'attendance_checkin_not_in_workplace_error'.tr;
    state.isInCheckInPositionRange = false;
    if (workplaceList.isNotEmpty) {
      for (var workplace in workplaceList) {
        OLogger.d('工作地点： ${workplace.latitude}  ${workplace.longitude}');
        double startLatitude = myPosition?.latitude ?? 0;
        double startLongitude = myPosition?.longitude ?? 0;
        final lngLat = workplace.getLngLat();
        double endLatitude = lngLat[1];
        double endLongitude = lngLat[0];
        if (startLatitude != 0 &&
            startLongitude != 0 &&
            endLatitude != 0 &&
            endLongitude != 0) {
          OLogger.d(
              '坐标  workplace endLatitude:$endLatitude endLongitude:$endLongitude myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
          final distance = _geoHelper?.distanceInMeters(
                  startLatitude, startLongitude, endLatitude, endLongitude) ??
              0;
          int range = workplace.errorRange ?? 100; // 默认 100 米
          OLogger.d('距离计算：$distance $range');
          if (distance != 0 && distance <= range) {
            state.currentAddress = workplace.placeName;
            state.isInCheckInPositionRange = true;
            nearLeastWorkplace = workplace;
            break;
          }
        } else {
          OLogger.e(
              ' 错误的坐标  workplace endLatitude:$endLatitude endLongitude:$endLongitude myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
        }
      }
      OLogger.d('找到最近的打卡点? ${nearLeastWorkplace?.placeName ?? '无'}');
    }
  }

  /// 每秒更新一次时间
  void updateTimePerSecond() {
    var time = DateTime.now();
    state.currentTime = time.hms();
  }

  void initBottomBar() {
    // 查询是否管理员 更新底部导航栏
    state.bottomTabs = <BottomNavigationBarItem>[
      BottomNavigationBarItem(
          icon: const Icon(Icons.location_on),
          activeIcon: const Icon(Icons.location_on),
          label: 'attendance_tab_checkin'.tr),
      BottomNavigationBarItem(
          icon: const Icon(Icons.pie_chart),
          activeIcon: const Icon(Icons.pie_chart),
          label: 'attendance_tab_statistic'.tr),
    ];
  }

  /// pageView
  void handlePageChanged(int page) {
    OLogger.d("切换pageView page:$page");
  }

  /// 底部栏
  void handleNavBarTap(int page) {
    state.currentIndex = page;
    pageViewController.jumpToPage(page);
  }

  /// 更新打卡记录
  void clickUpdateRecord(BuildContext context, AttendanceV2Record info) {
    if (info.isLastRecord) {
      OLogger.d('更新打卡，${info.checkInType}');
      O2UI.showConfirm(context, 'attendance_update_confirm_content'.tr,
          okPressed: () {
        _checkinClickOrUpdate(context,
            recordId: info.id, recordType: info.checkInType);
      });
    }
  }

  /// 打卡
  void clickCheckIn(BuildContext context) {
    OLogger.d('点击打卡');
    if (!state.todayNeedCheck) {
      OLogger.e('今日不需要打卡了，已经完成！');
      return;
    }
    _checkinClickOrUpdate(context);
  }

  /// 打卡处理
  ///
  /// @param recordId 更新打卡的id
  /// @param recordType 更新打卡的类型
  void _checkinClickOrUpdate(BuildContext context,
      {String? recordId, String? recordType}) {
    if (myPosition == null) {
      Loading.toast('attendance_checkin_need_location'.tr);
      return;
    }
    if (state.isInCheckInPositionRange && nearLeastWorkplace != null) {
      // 正常打卡
      OLogger.i('正常打卡！');
      // 计算checkin type
      try {
        String checkType = recordType ?? '';
        String id = recordId ?? '';
        if (checkType.isEmpty || id.isEmpty) {
          checkType = currentCheckItem?.checkInType ?? '';
          id = currentCheckItem?.id ?? '';
          // 检查打卡 限制时间
          var preDutyTimeBeforeLimit =
              currentCheckItem?.preDutyTimeBeforeLimit ?? '';
          var preDutyTimeAfterLimit =
              currentCheckItem?.preDutyTimeAfterLimit ?? '';
          if (!_checkLimitTime(preDutyTimeBeforeLimit, preDutyTimeAfterLimit)) {
            return;
          }
        }
        // '${myLocation!.address}'
        _postCheckIn('${myPosition!.latitude}', '${myPosition!.longitude}',
            myPosition!.address ?? '', checkType,
            workPlaceId: nearLeastWorkplace!.id ?? '',
            workAddress: nearLeastWorkplace!.placeName ?? '',
            id: id);
      } catch (e) {
        OLogger.e(e);
        Loading.toast('attendance_checkin_type_empty'.tr);
      }
    } else {
      // 外勤打开
      OLogger.i('外勤打卡');
      _outsideCheckIn(context, recordId: recordId, recordType: recordType);
    }
  }

  /// 是否有打卡时间限制
  bool _checkLimitTime(
      String preDutyTimeBeforeLimit, String preDutyTimeAfterLimit) {
    if (preDutyTimeBeforeLimit.isNotEmpty) {
      var now = DateTime.now();
      var today = now.ymd();
      var beforeTime = DateTime.tryParse("$today $preDutyTimeBeforeLimit:00");
      if (beforeTime != null && now.isBefore(beforeTime)) {
        Loading.toast('attendance_checkin_limit_time_error'
            .trArgs([preDutyTimeBeforeLimit, preDutyTimeAfterLimit]));
        return false;
      }
    }
    if (preDutyTimeAfterLimit.isNotEmpty) {
      var now = DateTime.now();
      var today = now.ymd();
      var afterTime = DateTime.tryParse("$today $preDutyTimeAfterLimit:00");
      if (afterTime != null && now.isAfter(afterTime)) {
        Loading.toast('attendance_checkin_limit_time_error'
            .trArgs([preDutyTimeBeforeLimit, preDutyTimeAfterLimit]));
        return false;
      }
    }
    return true;
  }

  /// 外勤打卡
  void _outsideCheckIn(BuildContext context,
      {String? recordId, String? recordType}) async {
    if (!allowFieldWork) {
      Loading.toast('attendance_checkin_outside_not_allow'.tr);
      return;
    }
    // 确认外勤打卡 dialog
    var result = await O2UI.showCustomDialog(
        context,
        'attendance_checkin_outside_dialog_title'.tr,
        TextField(
          controller: outsideCheckInDescInputController,
          maxLines: 1,
          style: Theme.of(context).textTheme.bodyMedium,
          keyboardType: TextInputType.text,
          textInputAction: TextInputAction.done,
          decoration: InputDecoration(
            hintText: 'attendance_checkin_outside_dialog_hint'.tr,
          ),
        ));
    OLogger.d('外勤打卡，返回结果$result');
    if (result != null && result == O2DialogAction.positive) {
      var desc = outsideCheckInDescInputController.text;
      if (desc.isEmpty && requiredFieldWorkRemarks) {
        Loading.toast('attendance_checkin_outside_dialog_hint'.tr);
      } else {
        // 计算checkin type
        try {
          String checkType = recordType ?? '';
          String id = recordId ?? '';
          if (checkType.isEmpty || id.isEmpty) {
            checkType = currentCheckItem?.checkInType ?? '';
            id = currentCheckItem?.id ?? '';
            // 检查打卡 限制时间
            var preDutyTimeBeforeLimit =
                currentCheckItem?.preDutyTimeBeforeLimit ?? '';
            var preDutyTimeAfterLimit =
                currentCheckItem?.preDutyTimeAfterLimit ?? '';
            if (!_checkLimitTime(
                preDutyTimeBeforeLimit, preDutyTimeAfterLimit)) {
              return;
            }
          }
          _postCheckIn('${myPosition!.latitude}', '${myPosition!.longitude}',
              myPosition!.address ?? '', checkType,
              signDesc: desc, isExternal: true, id: id);
        } catch (e) {
          OLogger.e(e);
          Loading.toast('attendance_checkin_type_empty'.tr);
        }
      }
    }
  }

  static final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();

  Future<String> _machineInfo() async {
    String deviceData = '';
    try {
      if (Platform.isAndroid) {
        deviceData = _readAndroidBuildData(await deviceInfoPlugin.androidInfo);
      } else if (Platform.isIOS) {
        deviceData = _readIosDeviceInfo(await deviceInfoPlugin.iosInfo);
      } else if (Platform.isLinux) {
        deviceData = _readLinuxDeviceInfo(await deviceInfoPlugin.linuxInfo);
      } else if (Platform.isMacOS) {
        deviceData = _readMacOsDeviceInfo(await deviceInfoPlugin.macOsInfo);
      } else if (Platform.isWindows) {
        deviceData = _readWindowsDeviceInfo(await deviceInfoPlugin.windowsInfo);
      }

      // ignore: empty_catches
    } on PlatformException {}
    return deviceData;
  }

  String _readAndroidBuildData(AndroidDeviceInfo build) {
    OLogger.d('Android 信息: $build');
    return '${build.brand}-${build.model}';
  }

  String _readIosDeviceInfo(IosDeviceInfo data) {
    OLogger.d('ios 信息: $data');
    return '${data.systemName}-${data.model}';
  }

  String _readLinuxDeviceInfo(LinuxDeviceInfo data) {
    OLogger.d('linux 信息: $data');
    return '${data.prettyName}-${data.buildId}';
  }

  String _readMacOsDeviceInfo(MacOsDeviceInfo data) {
    OLogger.d('macos 信息: $data');
    return '${data.arch}-${data.model}';
  }

  String _readWindowsDeviceInfo(WindowsDeviceInfo data) {
    OLogger.d('windows 信息: $data');
    return '${data.computerName}-${data.numberOfCores}';
  }
}
