import 'dart:async';

import 'package:flutter/material.dart';
import 'package:geolocation/models/position.dart';
import 'package:get/get.dart';
import 'package:o2oa_all_platform/common/extension/index.dart';

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

class OldCheckInController extends GetxController {
  OldCheckInController();

  final state = OldCheckInState();
  Record? lastRecord;
// 外勤打卡，需要输入说明
  final TextEditingController outsideCheckInDescInputController =
      TextEditingController();

  // 定时器
  Timer? _timer;
  GeolocatorHelper? _geoHelper;
  /// 当前定位信息
  GeoPosition? myPosition;

  // 工作地点
  List<WorkplaceInfo> workplaceList = [];
  WorkplaceInfo? nearLeastWorkplace; // 最近的打卡地点

  /// 在 onInit() 之后调用 1 帧。这是进入的理想场所
  @override
  void onReady() {
    /// 循环执行
    /// 间隔1秒
    _timer = Timer.periodic(const Duration(milliseconds: 1000), (timer) {
      ///定时任务
      _updateTimePerSecond();
    });
    // 初始化定位程序
    _geoHelper = GeolocatorHelper(callback: (position){
      myPosition = position;
      _calNearestWorkplace();
    });
    _geoHelper?.startLocation();

    // 初始化数据
    _loadAllWorkPalce();
    _loadRecordList();
    super.onReady();
  }

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

  _loadAllWorkPalce() async {
    final result = await AttendanceAssembleControlService.to.listAllAttendanceWorkPlace();
    if (result != null) {
      workplaceList.clear();
      workplaceList.addAll(result);
    }
  }
  _loadRecordList() async {
    final result = await AttendanceAssembleControlService.to.listMyRecords();
    if (result != null) {
      final rList = result.records ?? [];
      if (rList.isNotEmpty) {
        lastRecord = rList.last;
      }
      state.recordList.clear();
      var unCheckNumber = 0;
      final list = result.scheduleInfos?.map((s) {
          //是否已打卡
          final record = rList.firstWhereOrNull((element) => element.checkinType == s.checkinType);
          if (record != null) {
              s.checkinStatus =  'attendance_record_check_time'.tr;
              s.checkinTime = record.signTime;
              s.recordId = record.id;
              if (lastRecord != null && lastRecord?.id == record.id) {
                s.lastRecord = record;
              }
              unCheckNumber = 0; //清零
          }else{
              s.checkinStatus =  'attendance_uncheckin'.tr;
              unCheckNumber++;
          }
          return s;
      }).toList();
      state.recordList.addAll(list??[]);
      state.todayNeedCheck = (unCheckNumber > 0) ;
    } else {
      state.todayNeedCheck = false;
    }
  }
 
  /// 查找最近的打卡地点
  void _calNearestWorkplace() async {
    if (myPosition != null && workplaceList.isNotEmpty) {
      double minDistance = -1.0;
      for (var workplace in workplaceList) {
        OLogger.d('工作地点： ${workplace.latitude}  ${workplace.longitude}');
        double startLatitude = myPosition?.latitude ?? 0;
        double startLongitude = myPosition?.longitude ?? 0;
        double endLatitude = double.tryParse(workplace.latitude ?? '0') ?? 0;
        double endLongitude = double.tryParse(workplace.longitude ?? '0') ?? 0;
        if (startLatitude != 0 && startLongitude != 0 && endLatitude != 0 && endLongitude != 0) {
          OLogger.d('坐标  workplace endLatitude:$endLatitude endLongitude:$endLongitude myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
          final wgs84 = BaiduLocationTransformHelper.bd09towgs84(endLongitude, endLatitude);
          final wgs84Lng = wgs84[0];
          final wgs84Lat = wgs84[1];
          OLogger.d('转化后的gps 坐标   workplace wgs84Lat:$wgs84Lat wgs84Lng:$wgs84Lng myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
          final distance = _geoHelper?.distanceInMeters(startLatitude, startLongitude, wgs84Lat, wgs84Lng) ?? 0;
          int range = workplace.errorRange ?? 100; // 默认 100 米
          OLogger.d('距离计算：$distance $range');
          if (minDistance == -1.0) {
            minDistance = distance;
            nearLeastWorkplace = workplace;
          } else {
            if (minDistance > distance) {
              minDistance = distance;
              nearLeastWorkplace = workplace;
            }
          }
        } else {
          OLogger.e(' 错误的坐标  workplace endLatitude:$endLatitude endLongitude:$endLongitude myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
        }
      }
      OLogger.d('找到最近的打卡点? ${nearLeastWorkplace?.placeName ?? '无'}');
      _checkIsInWorkplace();
    } else {
      OLogger.e('还没有定位成功，或没有查询到工作列表！');
    }
  }
  /// 检查当前定位是否在打卡地点的范围内
  void _checkIsInWorkplace() async {
    if (myPosition != null && nearLeastWorkplace != null) {
      double startLatitude = myPosition?.latitude ?? 0;
        double startLongitude = myPosition?.longitude ?? 0;
        double endLatitude = double.tryParse(nearLeastWorkplace?.latitude ?? '0') ?? 0;
        double endLongitude = double.tryParse(nearLeastWorkplace?.longitude ?? '0') ?? 0;
        if (startLatitude != 0 && startLongitude != 0 && endLatitude != 0 && endLongitude != 0) {
          OLogger.d('坐标  workplace endLatitude:$endLatitude endLongitude:$endLongitude myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
          final wgs84 = BaiduLocationTransformHelper.bd09towgs84(endLongitude, endLatitude);
          final wgs84Lng = wgs84[0];
          final wgs84Lat = wgs84[1];
          OLogger.d('转化后的gps 坐标   workplace wgs84Lat:$wgs84Lat wgs84Lng:$wgs84Lng myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
          final distance = _geoHelper?.distanceInMeters(startLatitude, startLongitude, wgs84Lat, wgs84Lng) ?? 0;
          int range = nearLeastWorkplace?.errorRange ?? 100; // 默认 100 米
          if (distance != 0 &&  distance <= range) {
            state.currentAddress = nearLeastWorkplace!.placeName;
            state.isInCheckInPositionRange = true;
          } else {
            state.currentAddress = 'attendance_checkin_not_in_workplace_error'.tr;
            state.isInCheckInPositionRange = false;
          }
        } else {
          OLogger.e(' 错误的坐标  workplace endLatitude:$endLatitude endLongitude:$endLongitude myPosition startLatitude: $startLatitude startLongitude: $startLongitude');
        }
    }
  }
  /// 每秒更新一次时间
  void _updateTimePerSecond() {
    state.currentTime = DateTime.now().hms();
  }

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

  void clickUpdateRecord(Feature info) {
    final context = Get.context;
    if(context == null) {
      return;
    }
    O2UI.showConfirm(context, 'attendance_update_confirm_content'.tr, okPressed: (){
      _checkinClickOrUpdate(recordType: info.checkinType, recordId: info.lastRecord?.id);
    });
  }


  String _calCheckType() {
      final checkItem = state.recordList.firstWhereOrNull((element) => element.checkinStatus == 'attendance_uncheckin'.tr);
      if (checkItem != null) {
        return checkItem.checkinType ?? '';
      }
      return '';
  }
  ///
  /// 打卡处理
  /// 
  /// @param recordId 更新打卡的id
  /// @param recordType 更新打卡的类型
  void _checkinClickOrUpdate({String? recordId, String? recordType}) {
    if (myPosition == null) {
      Loading.toast('attendance_checkin_need_location'.tr);
      return;
    }
    if (state.isInCheckInPositionRange && nearLeastWorkplace != null) {
      // 正常打卡
      OLogger.d('正常打卡！');
      // 计算checkin type
      try {
        String checkType = recordType ?? '';
        String id = recordId ?? '';
        
        _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.d('外勤打卡');
      _outsideCheckIn(recordId: recordId, recordType: recordType);
    }
  }

   /// 外勤打卡
  void _outsideCheckIn({String? recordId, String? recordType}) async {
    final context = Get.context;
    if(context == null) {
      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;
      // 计算checkin type
      try {
        _postCheckIn('${myPosition!.latitude}', '${myPosition!.longitude}',
            '${myPosition!.address}', recordType ?? '',
            signDesc: desc, isExternal: true, id: recordId?? '');
      } catch (e) {
        OLogger.e(e);
        Loading.toast('attendance_checkin_type_empty'.tr);
      }
      
    }
  }

  ///
  /// 提交打卡
  ///
  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();
    final now = DateTime.now();
    var post = MobileCheckPost(
       latitude: latitude,
       longitude: longitude,
       recordAddress: addrStr,
       workAddress: workPlaceId,
       checkin_type: checkType,
      isExternal: isExternal,
      description: signDesc,
      signTime: now.hms(),
      recordDateString: now.ymd()
    );
    if (id.isNotEmpty) {
      post.id = id;
    }
    var deviceType = SharedPreferenceService.to.getString(SharedPreferenceService.currentDeviceTypeKey);
    post.optMachineType = deviceType;
    var iddata = await AttendanceAssembleControlService.to.checkInPost(post);
    if (iddata != null) {
      Loading.dismiss();
      _loadRecordList();
    }
  }
}
