import 'dart:async';
import 'dart:math';

import 'package:fis_common/logger/logger.dart';
import 'package:fis_jsonrpc/rpc.dart';
import 'package:fis_jsonrpc/services/device.m.dart';
import 'package:flyinsono/architecture/router/index.dart';
import 'package:flyinsono/managers/interfaces/device.dart';
import 'package:flyinsono/rpc.dart';
import 'base_manager.dart';
import 'interfaces/entities/device_entities.dart';

class DeviceManager extends BaseManager implements IDeviceManager {
  final _heartbeatTimerMap = <String, Timer>{};

  @override
  Future<DeviceExtendInfoDTO?> getDeviceInfo(String deviceCode) async {
    try {
      return await rpc.device.getDeviceInfoAsync(
        GetDeviceRequest(
          token: token,
          deviceCode: deviceCode,
        ),
      );
    } catch (e) {
      logger.e("[DeviceManager] get device by code error.", e);
    }
    return null;
  }

  @override
  Future<PageCollection<DeviceExtendInfoDTO>?> getUserDevicePagedList(
    int pageIndex,
    int pageSize, {
    String? keyword,
    bool? isOnline,
  }) async {
    try {
      final result = await rpc.device.getPersonDeviceListAsync(
        GetPersonDeviceRequest(
          token: token,
          pageIndex: pageIndex,
          pageSize: pageSize,
          keyWord: keyword,
          isOnline: isOnline,
        ),
      );
      return result;
    } catch (e) {
      logger.e(
          "[DeviceManager] get paged device list of current user error.", e);
    }
    return null;
  }

  ///根据设备短码获取设备信息
  ///
  ///[shortCode] 设备短码
  Future<DeviceExtendInfoDTO?> getDeviceByShortCode(String shortCode) async {
    try {
      return await rpc.device.getDeviceByShortCodeAsync(
        GetDeviceByShortCodeRequest(
          token: token,
          shortCode: shortCode,
        ),
      );
    } catch (e) {
      logger.e("[DeviceManager] get device by shortCode error.", e);
    }
    return null;
  }

  //分享设备直播
  Future<String?> shareDeviceLive(String deviceCode) async {
    try {
      final result = await rpc.device.createLiveShareInfoAsync(
        CreateLiveShareInfoRequest(
          token: token,
          deviceCode: deviceCode,
        ),
      );
      return result.shareUrl;
    } catch (e) {
      logger.e("[DeviceManager] create device live share info error.", e);
    }
    return null;
  }

  @override
  Future<void> openRemoteControllerPage(
    String deviceCode, {
    bool isLiveConsultationController = false,
    String consultationCode = '',
  }) async {
    try {
      // if (FPlatform.isPureWeb && Store.app.enableNewTab) {
      //   final url = html.window.location.origin;
      //   final token = Store.user.token;
      //   html.window.open(
      //       '$url/index.html?page=remoteController&deviceCode=$deviceCode&token=$token',
      //       '');
      //   return;
      // }
      await router.to(
        RouteNames.Live.RemoteController,
        parameters: {
          'deviceCode': deviceCode,
          "isLiveConsultationController":
              isLiveConsultationController.toString(),
          'consultationCode': consultationCode,
        },
      );
    } catch (e) {
      logger.e("[DeviceManager] openRemoteControllerPage", e);
    }
  }

  @override
  Future<DeviceLiveDisplayInfoModel?> enterLiveRoom(String deviceCode) async {
    try {
      final result = await rpc.device.joinDeviceLiveRoomAsync(
        JoinDeviceLiveRoomRequest(
          token: token,
          deviceCode: deviceCode,
        ),
      );
      _startSendHeartbeat(
        deviceCode,
        result.reportStateIntervalSeconds,
      ); // 心跳开始

      final sources = result.videoDeviceInfos!.map((e) {
        final data = e.liveData!;
        return DeviceLiveSourceInfoModel(
          httpFlvUrl: data.httpPullUrl!,
          rtmpUrl: data.rtmpPullUrl!,
          width: data.width,
          height: data.height,
        );
      }).toList();
      final model = DeviceLiveDisplayInfoModel(
        useMerge: result.mergedChannel,
        mergeWidth: result.mergedVideoOutputWidth,
        mergeHeight: result.mergedVideoOutputHeight,
        isOldPlatform: result.isOldPlatform,
        sources: sources,
      );
      model.dto = result; //TODO[melon]: temp
      return model;
    } catch (e) {
      logger.e(
          "[DeviceManager] enter live room error, deviceCode: $deviceCode.", e);
    }
    return null;
  }

  @override
  Future<bool> exitLiveRoom(String deviceCode) async {
    try {
      final result = await rpc.device.leaveDeviceLiveRoomAsync(
        LeaveDeviceLiveRoomRequest(
          token: token,
          deviceCode: deviceCode,
        ),
      );

      _stopSendHeartbeat(deviceCode);

      return result;
    } catch (e) {
      logger.e(
          "[DeviceManager] exit live room error, deviceCode: $deviceCode.", e);
    }
    return false;
  }

  @override
  Future<void> sendHeartbeat(String deviceCode) async {
    try {
      rpc.device.reportLiveViewStateAsync(
        ReportLiveViewStateRequest(
          token: token,
          deviceCode: deviceCode,
        ),
      );
    } catch (e) {
      logger.e(
          "[DeviceManager] send heartbeat error, deviceCode: $deviceCode.", e);
    }
  }

  /// 开始发送心跳
  Future<void> _startSendHeartbeat(
      String deviceCode, int intervalSeconds) async {
    final int safeIntervalSeconds = max(120, intervalSeconds); // 最小安全间隔时间为 120s
    final intervalMillseconds = 1000 * safeIntervalSeconds - 300; // 设置提前点

    // 如果已存在先取消
    if (_heartbeatTimerMap[deviceCode] is Timer) {
      _heartbeatTimerMap[deviceCode]?.cancel();
      logger.i(
          "[DeviceManager] heartbeat timer already set, cancel first, deviceCode: $deviceCode ");
    }

    _heartbeatTimerMap[deviceCode] = Timer.periodic(
      Duration(milliseconds: intervalMillseconds),
      (timer) {
        sendHeartbeat(deviceCode);
      },
    );

    // 立即发送一次心跳
    sendHeartbeat(deviceCode);
  }

  /// 停止发送心跳
  Future<void> _stopSendHeartbeat(String deviceCode) async {
    _heartbeatTimerMap[deviceCode]?.cancel();
    _heartbeatTimerMap.remove(deviceCode);
  }
}
