import 'dart:convert';
import 'dart:html';
import 'dart:typed_data';
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:fluttertoast/fluttertoast.dart';

import 'package:colorize_logger/colorize_logger.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get_it/get_it.dart';
import 'package:http/http.dart' as http;
import 'package:sprintf/sprintf.dart';
import 'package:ustest/Services/DeviceService.dart';

class DeviceInfoView extends StatefulWidget {
  DeviceInfoView();

  @override
  _DeviceInfoViewState createState() => _DeviceInfoViewState();
}

class _DeviceInfoViewState extends State<DeviceInfoView> {
  late List<File> _files;
  String _uniqueCode = "xxxxxx";
  String _token = "xxxxxx";
  String _examCode = "";

  final _filesController = TextEditingController();
  final _connectTextController = TextEditingController(
      text: '{"jsonrpc": "2.0",'
          '"method": "ConnectAsync",'
          '"params": [{'
          '"DeviceUniqueCode": "4914352a75f645279f6b4ad6764cc288",'
          '"Password": "4914352a75f645279f6b4ad6764cc288",'
          '"DeviceModel": "E30",'
          '"DeviceType": "US",'
          '"SoftwareVersion": "1.11.0",'
          '"SystemVersion": "2.2.27.5",'
          '"CPUModel": "I5-10400",'
          '"Description": "自测设备",'
          '"Name": "ZCSB",'
          '"Organ": "Organization_20220608060137EVEo3p",'
          '"SystemLanguage": "Chinese"'
          '}],'
          '"id": 1 }');

  final _channel = WebSocketChannel.connect(
    Uri.parse('ws://192.168.6.20:9301?token=8557855B64474684B45294B75B1EDBA1'),
  );

  @override
  void initState() {
    getDeviceInfo();
    super.initState();
  }

  void getDeviceInfo() async {
    try {
      var request = _connectTextController.text;
      var service = GetIt.instance.get<DeviceService>();
      var device = await service.getDeviceDetail(request);

      setState(() {
        _uniqueCode = device.uniqueCode;
        _token = device.token;
      });
    } catch (ex) {
      print("initState ex" + ex.toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: Container(
              padding: const EdgeInsets.fromLTRB(20, 30, 20, 20),
              child: Column(children: [
                Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Row(
                    children: [
                      Expanded(
                          child: TextField(
                        controller: _connectTextController,
                        keyboardType: TextInputType.multiline,
                        textInputAction: TextInputAction.newline,
                        decoration: InputDecoration(
                            border: const OutlineInputBorder(),
                            labelText: "请求数据"),
                        minLines: 1,
                        maxLines: 5,
                      )),
                      TextButton(
                          onPressed: onConnect, child: const Text("Connect"))
                    ],
                  ),
                ),
                Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Row(
                      children: [Text("超声机设备Id"), Text("Device12345678")],
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    )),
                Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Row(
                      children: [Text("超声机唯一码"), Text(_uniqueCode)],
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    )),
                Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Row(
                      children: [
                        Text("Token"),
                        Expanded(
                            child: Text(
                          _token,
                        ))
                      ],
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    )),
                Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Row(
                      children: [
                        Text("创建检查"),
                        Text(_examCode),
                      ],
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    )),
                Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Row(
                      children: [
                        Expanded(
                          child: TextField(
                            restorationId: "file",
                            keyboardType: TextInputType.text,
                            decoration: InputDecoration(
                                border: const OutlineInputBorder(),
                                labelText: "请选择一个vid和一个对应缩略图jpg文件"),
                            maxLength: 1,
                            controller: _filesController,
                          ),
                        ),
                        TextButton(
                          onPressed: _onBrowse,
                          child: Text("Browse"),
                        )
                      ],
                    )),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    TextButton.icon(
                        onPressed: onCreateExamPressed,
                        icon: Icon(Icons.add),
                        label: Text("开始检查")),
                    TextButton.icon(
                        onPressed: onUploadPressed,
                        icon: Icon(Icons.upload_file),
                        label: Text("上传图像")),
                    TextButton.icon(
                        onPressed: onFinshExanPressed,
                        icon: Icon(Icons.done_all),
                        label: Text("结束检查"))
                  ],
                ),
                StreamBuilder(
                  stream: _channel.stream,
                  builder: (context, snapshot) {
                    var message = "";
                    // var message =
                    //     snapshot.hasData ? '${snapshot.data}' : 'no message';
                    if (snapshot.hasData) {
                      var uint8Array =
                          Uint8List.fromList(snapshot.data as List<int>);
                      var byteData = uint8Array.buffer.asByteData();
                      var byteDataLength = byteData.lengthInBytes;
                      var messageConentList =
                          Uint8List.view(uint8Array.buffer, 0, byteDataLength);
                      var messageConentLength = messageConentList.length;
                      var messageConent = Uint8List.fromList(messageConentList);
                      var messageText = Utf8Decoder().convert(messageConent);
                      Map<String, dynamic> messageObject =
                          jsonDecode(messageText);
                      //通知类型区分
                      if (messageObject["NotificationType"] as int ==
                          NotificationTypeEnum.ConnectionNotification.index) {
                        var connectionNotification =
                            ConnectionNotification.fromJson(messageObject);
                        print(
                            "connectionNotification.NotificationType:${connectionNotification.notificationType}");
                      } else if (messageObject["NotificationType"] as int ==
                          NotificationTypeEnum.DisconnectNotification.index) {
                        var disconnectNotification =
                            DisconnectNotification.fromJson(messageObject);
                        print(
                            "disconnectNotification.NotificationType:${disconnectNotification.notificationType}");
                      }
                      message = messageText;
                    }
                    return new Padding(
                      padding: const EdgeInsets.symmetric(vertical: 24.0),
                      child: new Text(message),
                    );
                  },
                )
              ]))),
    );
  }

  @override
  void dispose() {
    //_channel.sink.close();
    super.dispose();
  }

  void onConnect() async {
    try {
      var request = _connectTextController.text;
      var service = GetIt.instance.get<DeviceService>();
      var device = await service.connectAsync(request);

      setState(() {
        _uniqueCode = device.uniqueCode;
        _token = device.token;
      });
    } catch (ex) {
      print("_token ex" + ex.toString());
    }
  }

  void _onBrowse() {
    var uploadInput = new FileUploadInputElement();
    uploadInput.multiple = true;
    //uploadInput.accept = '*.vid';
    uploadInput.click();
    uploadInput.onChange.listen(
      (changeEvent) {
        _files = uploadInput.files!;

        for (var i = 0; i < _files.length; i++) {
          _filesController.text += _files[i].name + ';';
        }
      },
    );
  }

  void _onProgress(ProgressEvent e) {
    print("upload progress is" + e.total.toString());
  }

  Future<String> uploadFileToSever(File file) async {
    var url = '';
    try {
      print('File Name:' + file.name);
      var client = http.Client();
      var body = sprintf(
          '{"jsonrpc": "2.0", "method": "GetAuthorizationAsync", "params": [{"Token": "%s",  "FileName": "%s", "ApplicantTypeEnum": 1  }], "id": 1 }',
          [_token, file.name]);
      final response = await client.post(
          Uri.parse('http://192.168.6.20:8303/IStorageService'),
          body: body);
      print('GetAuthorizationAsync response.body' + response.body);
      final parsed = jsonDecode(response.body);
      var authorization = parsed['result']['Authorization'].toString();
      url = parsed['result']['StorageUrl'].toString();
      print('GetAuthorizationAsync result' + authorization);

      final headers = {"Authorization": authorization};

      var formData = new FormData();
      formData.appendBlob('file', file);
      await HttpRequest.request(url,
              method: 'PUT',
              sendData: formData,
              requestHeaders: headers,
              onProgress: _onProgress)
          .then((value) {
        var data = value;
        var responseText = data.responseText!;
        final parsed = jsonDecode(responseText);
        var reuslt = parsed['IsSuccess'];
        Logger.info(
            "status:" + data.status.toString() + ",isSuccess:" + reuslt);
      }).catchError((onError) {
        Logger.error(onError);
      });
    } catch (ex) {
      print(ex);
    }
    return url;
  }

  void onUploadPressed() async {
    if (_examCode == "") {
      showToast("请先开始一个检查");
      return;
    }

    var privewUrl = '';
    var vidUrl = '';
    for (var i = 0; i < _files.length; i++) {
      var name = _files[i].name;
      if (name.endsWith(".VID")) {
        vidUrl = await uploadFileToSever(_files[i]);
        Logger.info("Vid File upload to " + vidUrl);
      } else {
        privewUrl = await uploadFileToSever(_files[i]);
        Logger.info("Preview File upload to " + privewUrl);
      }
    }

    var client = http.Client();
    //update data
    var body = sprintf(
        '{"jsonrpc": "2.0", "method": "UploadExamDataAsync", "params": [{"Token": "%s",  "ExamCode": "%s", "PreviewFileToken": "%s", "FileToken": "%s","Application": "腹部", "PatientScanType": "Routine"  }], "id": 1 }',
        [_token, _examCode, privewUrl, vidUrl]);
    print('UploadExamData http.Client()' + body);
    final response2 = await client.post(
        Uri.parse('http://192.168.6.20:8303/IRemedicalService'),
        body: body);
    print('UploadExamData response.body' + response2.body);
    final parsed2 = jsonDecode(response2.body);
    var resutlt = parsed2['result'].toString();
    print('UploadExamData result ' + resutlt);
  }

  void onCreateExamPressed() async {
    var client = http.Client();

    var body = sprintf(
        '{"jsonrpc": "2.0", "method": "CreateExamInfoAsync", "params": [{"Token": "%s",  "PatientType": "Person", "PatientInfo": [{"Name":"張三","IdentityCard":"320525198806110078","Sex":"2","Age":"34"}]  }], "id": 1 }',
        [_token]);
    print('CreateExamInfo http.Client()' + body);
    final response = await client.post(
        Uri.parse('http://192.168.6.20:8303/IRemedicalService'),
        body: body);
    print('CreateExamInfo response.body' + response.body);
    final parsed = jsonDecode(response.body);
    var examCode = parsed['result']['ExamCode'].toString();
    print('CreateExamInfo result examCode' + examCode);
    setState(() {
      _examCode = examCode;
    });
    //client.close();
  }

  void onFinshExanPressed() async {
    if (_examCode == "") {
      showToast("No exam to finish");
      return;
    }

    var client = http.Client();

    try {
      var body = sprintf(
          '{"jsonrpc": "2.0", "method": "DeviceFinishExamAsync", "params": [{"Token": "%s",  "Records":["%s"]}], "id": 1 }',
          [_token, _examCode]);
      print('FinishExam http.Client()' + body);
      final response = await client.post(
          Uri.parse('http://192.168.6.20:8303/IRemedicalService'),
          body: body);
      print('FinishExam response.body' + response.body);
      final parsed = jsonDecode(response.body);
      var result = parsed['result'] as bool;
      print('FinishExam result examCode' + result.toString());
      setState(() {
        _examCode = "";
      });
      //client.close();

    } catch (ex) {
      print('FinishExam.to ex' + ex.toString());
    }
  }

  void showToast(String msg) {
    Fluttertoast.showToast(
        msg: msg,
        toastLength: Toast.LENGTH_SHORT,
        gravity: ToastGravity.CENTER,
        timeInSecForIosWeb: 1,
        backgroundColor: Colors.red[500],
        textColor: Colors.white,
        fontSize: 16.0);
  }
}

enum NotificationTypeEnum {
 /// <summary>
  /// Unknown|0| 未知
  /// </summary>
  Unknown,

  /// <summary>
  /// ChatMsgNotification|1| 聊天通知
  /// </summary>
  ChatMsgNotification,

  /// <summary>
  /// TokenReplacedNotification|2| 账号被替换登出通知
  /// </summary>
  TokenReplacedNotification,

  /// <summary>
  /// DisconnectNotification| 3|与服务器断开连接通知
  /// </summary>
  DisconnectNotification,

  /// <summary>
  /// ConnectionNotification| 4|	与服务器已连接通知
  /// </summary>
  ConnectionNotification,

  /// <summary>
  /// ExamRecordsFinishedNotification| 5 | 完成检查通知
  /// </summary>
  ExamRecordsFinishedNotification,

  /// <summary>
  /// RejectApplyConsultationNotification| 6 | 拒绝预约申请的通知
  /// </summary>
  RejectApplyConsultationNotification,

  /// <summary>
  /// CancelInvitingInLiveConsultationNotification| 7 | 取消会诊过程中邀请其他成员的通知
  /// </summary>
  CancelInvitingInLiveConsultationNotification,

  /// <summary>
  /// InviteInLiveConsultationNotification| 8 | 会诊过程中邀请其他成员的通知
  /// </summary>
  InviteInLiveConsultationNotification,

  /// <summary>
  /// InviteInLiveConsultationNotification| 9 | 会诊开始前提醒的通知
  /// </summary>
  ConsultationRemindNotification,

  /// <summary>
  /// PasswordExpiredWarningNotification| 10 | 用户密码过期预警通知
  /// </summary>
  PasswordExpiredWarningNotification,

  /// <summary>
  /// InviteLiveConsultationNotification| 11 | 开始会诊的通知
  /// </summary>
  InviteLiveConsultationNotification,

  /// <summary>
  /// AcceptLiveConsultationNotification| 12 | 接受会诊的通知
  /// </summary>
  AcceptLiveConsultationNotification,

  /// <summary>
  /// RejectLiveConsultationNotification| 13 | 拒绝会诊的通知
  /// </summary>
  RejectLiveConsultationNotification,

  /// <summary>
  /// InviteLiveConsultationToDeviceNotification| 14 | 开始会诊通知 to 设备端
  /// </summary>
  InviteLiveConsultationToDeviceNotification,

  /// <summary>
  /// CancelLiveConsultationNotification| 15 | 取消会诊通知
  /// </summary>
  CancelLiveConsultationNotification,

  /// <summary>
  /// CloseLiveConsultationNotification| 16 | 关闭会诊通知
  /// </summary>
  CloseLiveConsultationNotification,

  /// <summary>
  /// JoinLiveConsultationNotification| 17 | 进入会诊通知
  /// </summary>
  JoinLiveConsultationNotification,

  /// <summary>
  /// NetworkErrConsultationNotification| 18 | 网络质量不佳会诊通知
  /// </summary>
  NetworkErrConsultationNotification,

  /// <summary>
  /// LeaveConsultationNotification| 19 | 离开会诊通知
  /// </summary>
  LeaveConsultationNotification,

  /// <summary>
  /// JoinInLiveConsultationNotification| 20 | 会诊中加入房间
  /// </summary>
  JoinInLiveConsultationNotification,

  /// <summary>
  /// RejectLiveConsultationNotification| 21 | 拒绝会诊的通知
  /// </summary>
  RejectInviteLiveConsultationNotification,

  /// <summary>
  /// ApplyConsultationNotification| 22 | 会诊申请通知
  /// </summary>
  ApplyConsultationNotification,

  /// <summary>
  /// ApprovalApplyConsultationNotification| 23 | 批准申请会诊通知
  /// </summary>
  ApprovalApplyConsultationNotification,

  /// <summary>
  /// InviteeConsultationNotification| 24 | 会诊受邀请人通知
  /// </summary>
  InviteeConsultationNotification,

  /// <summary>
  /// InviteeApproveApplyConsultationNotification| 25 | 会诊受邀请参与人同意通知
  /// </summary>
  InviteeApproveApplyConsultationNotification,

  /// <summary>
  /// InviteeRejectApplyConsultationNotification| 26 | 会诊受邀请参与人拒绝通知
  /// </summary>
  InviteeRejectApplyConsultationNotification,

  /// <summary>
  /// MuteLiveConsultationNotification| 27 | 开启关闭静音
  /// </summary>
  MuteLiveConsultationNotification,

  /// <summary>
  /// SwitchLiveConsultationVideoNotification| 28 | 开启关闭视频
  /// </summary>
  SwitchLiveConsultationVideoNotification,

  /// <summary>
  /// HeartRateJoinConsultationNotification| 29 | 会诊心跳,进入房间
  /// </summary>
  HeartRateJoinConsultationNotification,

  /// <summary>
  /// HeartRateLeaveConsultationNotification| 30 | 会诊心跳,离开房间
  /// </summary>
  HeartRateLeaveConsultationNotification,

  /// <summary>
  /// CloseLiveConsultationToDeviceNotification| 31 | 关闭会诊通知 to 设备端
  /// </summary>
  CloseLiveConsultationToDeviceNotification,

  /// <summary>
  /// CancelLiveConsultationToDeviceNotification| 32 | 取消会诊通知 to 设备端
  /// </summary>
  CancelLiveConsultationToDeviceNotification
}

class ConnectionNotification {
  NotificationTypeEnum notificationType;
  ConnectionNotification({
    this.notificationType = NotificationTypeEnum.Unknown,
  });
  factory ConnectionNotification.fromJson(Map<String, dynamic> map) {
    return ConnectionNotification(
      notificationType: NotificationTypeEnum.values
          .firstWhere((e) => e.index == map['NotificationType']),
    );
  }
}

class DisconnectNotification {
  NotificationTypeEnum notificationType;
  DisconnectNotification({
    this.notificationType = NotificationTypeEnum.Unknown,
  });
  factory DisconnectNotification.fromJson(Map<String, dynamic> map) {
    return DisconnectNotification(
      notificationType: NotificationTypeEnum.values
          .firstWhere((e) => e.index == map['NotificationType']),
    );
  }
}