
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:cached_network_image/cached_network_image.dart';
import 'package:dio/dio.dart';
// import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:hive/hive.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';

import '../constants.dart';
import '../events/eventbus.dart';
import '../events/events.dart';
import '../generated/l10n.dart';
import '../models/comment.dart';
import '../models/order.dart';
import '../models/payment_platform.dart';
import '../models/user.dart';
import '../routes.dart';
import '../store/actions.dart';
import '../store/store.dart';
import '../widgets/general/e_transfer_pay.dart';
import 'http_util.dart';
import 'utils.dart';

typedef void OnGotFile(int imageId, String filePath);

class Util {
  static final Util _util = Util._internal();
  factory Util() {
    return _util;
  }
  Util._internal();

  // final FirebaseMessaging firebaseMessaging = FirebaseMessaging();
  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
  static bool notificationTapped = false;

  init() {
    // initLocalNotification();
    // initFirebaseMessaging();

    // ePmqRwRUTmKuFNfbHA-6zq:APA91bEFEQx1YgJqfx0V0VYo86uRDGjG6SP1SPCAZW4OvQ7gMOeKWDQ47bfuEM00YavtKq7ZGpsWfFL7B3ypm00ZA6crjJJLK_-j_H8bS_dnQbLFwyRcW67IXCs5sRkro71bRZv7L1WM

    // eventBus.on<SubscribeToTopic>().listen((event) {
    //   if (firebaseMessaging != null) {
    //     firebaseMessaging.subscribeToTopic(event.topic);
    //   }
    // });
    // eventBus.on<UnSubscribeToTopic>().listen((event) {
    //   if (firebaseMessaging != null) {
    //     firebaseMessaging.unsubscribeFromTopic(event.topic);
    //   }
    // });
  }

  initLocalNotification() async {
    var initializationSettingsAndroid = new AndroidInitializationSettings('ic_launcher');
    var initializationSettingsIOS = new IOSInitializationSettings(
        onDidReceiveLocalNotification: onDidReceiveLocalNotification);
    var initializationSettings = new InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsIOS,
    );
    await flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onSelectNotification: onSelectNotification);
  }

  Future onSelectNotification(String payload, {bool replace=false}) async {
    print('payload: $payload');
    if (payload != null && payload.isNotEmpty) {
      Routes.router.navigateTo(store.state.context, payload, replace: replace);
    }
  }

//   initFirebaseMessaging() {
//     if (Platform.isIOS) {
//       iosPermission();
//     }
//     firebaseMessaging.getToken().then((token) {
//       print('FCM token: $token');
//       store.dispatch(UpdateFcmToken(token));
//     });
//     firebaseMessaging.configure(
//       onMessage: (Map<String, dynamic> message) {
//         print('FCM onMessage: $message');
// //        eventBus.fire(OnFcmReceived(message));
//         showNotificationWithDefaultSound(message);
//         return;
//       },
//       onBackgroundMessage: Platform.isIOS ? null : backgroundMessageHandler,
//       onResume: (Map<String, dynamic> message) {
//         print('FCM onResume: $message');
//         if (Platform.isAndroid) {
//           if (message != null && message['data'] != null && message['data']['route'] != null) {
//             notificationTapped = true;
//             onSelectNotification(message['data']['route']);
//           }
//         } else {
//           if (message != null && message['route'] != null) {
//             notificationTapped = true;
//             onSelectNotification(message['route']);
//           }
//         }
//         return;
//       },
//       onLaunch: (Map<String, dynamic> message) {
//         print('FCM onLaunch: $message');
//         if (Platform.isAndroid) {
//           if (message != null && message['data'] != null && message['data']['route'] != null) {
//             notificationTapped = true;
//             onSelectNotification(message['data']['route'], replace: true);
//           }
//         } else {
//           if (message != null && message['route'] != null) {
//             notificationTapped = true;
//             onSelectNotification(message['route'], replace: true);
//           }
//         }
//         return;
//       },
//     );
//   }

  Future onDidReceiveLocalNotification(int id, String title, String body, String payload) async {
    showDialog(
      context: store.state.context,
      builder: (BuildContext context) => CupertinoAlertDialog(
        title: Text(title),
        content: Text(body),
        actions: [
          CupertinoDialogAction(
            isDefaultAction: true,
            child: Text(S.of(context).ok),
            onPressed: () async {
              Navigator.of(context, rootNavigator: true).pop();
              if (payload != null && payload.isNotEmpty) {
                Routes.router.navigateTo(context, payload);
              }
            },
          )
        ],
      ),
    );
  }

  Future showNotificationWithDefaultSound(Map<String, dynamic> message) async {
    var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
      'channelId',
      'channelName',
      'channelDescription',
      importance: Importance.max,
      priority: Priority.high,
    );
    var iOSPlatformChannelSpecifics = new IOSNotificationDetails(presentSound: true, badgeNumber: 1);
    var platformChannelSpecifics = new NotificationDetails(
      android: androidPlatformChannelSpecifics,
      iOS: iOSPlatformChannelSpecifics,
    );
    await flutterLocalNotificationsPlugin.show(
      0,
      Platform.isAndroid ? message['notification']['title'] : message['title'],
      Platform.isAndroid ? message['notification']['body'] : message['body'],
      platformChannelSpecifics,
      payload: Platform.isAndroid ? message['data']['route'] : message['route'],
    );
  }

  // iosPermission() {
  //   firebaseMessaging.requestNotificationPermissions(
  //       const IosNotificationSettings(
  //         sound: true,
  //         badge: true,
  //         alert: true,
  //       )
  //   );
  //   firebaseMessaging.onIosSettingsRegistered.listen((IosNotificationSettings settings) {
  //     print('IOS settings registered: $settings');
  //   });
  // }

  static Future<dynamic> backgroundMessageHandler(Map<String, dynamic> message) {
    print('FCM background message handler: $message');
    return Future<void>.value();
  }

  static Future<Box> getBox() async {
    final dir = await getApplicationDocumentsDirectory();
    Hive.init(dir.path);
    Box box = await Hive.openBox('app_data');
    return box;
  }

  static Widget showImage(String imageUrl, {double width, double height,
    BoxFit fit, Widget Function(BuildContext, String, dynamic) errorWidget}) {
    if (imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('https:')) {
      return CachedNetworkImage(
        imageUrl: imageUrl,
        width: width,
        height: width,
        fit: fit,
        placeholder: (context, url) => Utils.imageLoadingIndicator(width: width, height: height),
        errorWidget: errorWidget != null ? errorWidget : (context, url, error) {
          return Image.asset(
            'assets/images/not_found.png',
            width: width,
            height: height,
            fit: fit,
          );
        },
      );
    } else if (imageUrl != null && imageUrl.isNotEmpty) {
      return Image.file(
        File(imageUrl),
        width: width,
        height: height,
        fit: fit,
        errorBuilder: (BuildContext context, Object object, StackTrace stackTrace) {
          return Image.asset(
            'assets/images/not_found.png',
            width: width,
            height: height,
            fit: fit,
          );
        },
      );
    } else {
      return Image.asset(
        'assets/images/not_found.png',
        width: width,
        height: height,
        fit: fit,
      );
    }
  }

  static void openWebUrl(BuildContext context, String link) {
    Routes.router.navigateTo(context, '/webview/$link');
  }

  AlertDialog getPicture(BuildContext context, User user, {int commentId = -1, int orderId = 0}) {
    return AlertDialog(
      title: Text(
        S.of(context).get_picture,
      ),
      content: Container(
        height: 130.0,
        child: Column(
          children: <Widget>[
            Container(
              margin: EdgeInsets.only(bottom: 12.0),
              child: Text(
                S.of(context).get_picture_from,
                style: TextStyle(
                  fontSize: 15.0,
                  color: Colors.black26,
                ),
              ),
            ),
            Container(
              child: TextButton(
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    Icon(
                      Icons.photo_library,
                    ),
                    Container(
                      margin: EdgeInsets.only(left: 5.0),
                      child: Text(
                        S.of(context).gallery,
                      ),
                    ),
                  ],
                ),
                onPressed: () {
                  getPictureFromGallery(context, user, commentId: commentId, orderId: orderId);
                },
              ),
            ),
            Container(
              child: TextButton(
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    Icon(
                      Icons.photo_camera,
                    ),
                    Container(
                      margin: EdgeInsets.only(left: 5.0),
                      child: Text(
                        S.of(context).camera,
                      ),
                    ),
                  ],
                ),
                onPressed: () {
                  getPictureFromCamera(context, user, commentId: commentId, orderId: orderId);
                },
              ),
            )
          ],
        ),
      ),
    );
  }

  void getPictureFromGallery(BuildContext context, User user, {int commentId = -1, int orderId = 0}) async {
    final picker = ImagePicker();
    var image = await picker.pickImage(source: ImageSource.gallery);
    Navigator.of(context).pop();
    uploadPicture(context, File(image.path), user, commentId: commentId, orderId: orderId);
  }

  void getPictureFromCamera(BuildContext context, User user, {int commentId = -1, int orderId = 0}) async {
    final picker = ImagePicker();
    var image = await picker.pickImage(source: ImageSource.camera);
    Navigator.of(context).pop();
    uploadPicture(context, File(image.path), user, commentId: commentId, orderId: orderId);
  }

  void uploadPicture(BuildContext context, File image, User user, {int commentId = -1, int orderId = 0}) async {
    if (await image.exists()) {
      print('image: ${image.path}');
      String imageName = basename(image.path);
      MultipartFile imageFile = await MultipartFile.fromFile(image.path, filename: imageName);
      Map<String, dynamic> formMap = {
        'id': user.id,
        'file': imageFile,
      };
      if (commentId >= 0) {
        formMap = {
          'contact_id': user.id,
          'comment_id': commentId,
          'order_id': orderId,
          'file': imageFile,
        };
        HttpUtil.httpPost(
          'v1/upload-comment-image',
              (response) {
            eventBus.fire(new OnCommentUpdatedEvent(Comment.fromJson(response.data)));
          },
          isFormData: true,
          body: formMap,
          sendProgress: (int sent, int total) {
            if (sent == total) {
              eventBus.fire(OnUploadCommentImageProgressEvent(false, 0.0));
            } else {
              eventBus.fire(OnUploadCommentImageProgressEvent(true, sent / total));
            }
          },
        ).catchError((error) {
          Utils.showMessageDialog(context, error);
        });
      } else {
        HttpUtil.httpPost(
          'v1/upload-avatar',
              (response) {
            store.dispatch(new UpdateCurrentUser(User.fromJson(response.data)));
            eventBus.fire(new OnCurrentUserUpdated());
          },
          isFormData: true,
          body: formMap,
          sendProgress: (int sent, int total) {
            if (sent == total) {
              eventBus.fire(OnProgressEvent(false, 0.0));
            } else {
              eventBus.fire(OnProgressEvent(true, sent / total));
            }
          },
        ).catchError((error) {
          Utils.showMessageDialog(context, error);
        });
      }
    }
  }

  AlertDialog getPicture2(BuildContext context, int imageId, OnGotFile onGotFile) {
    return AlertDialog(
      title: Text(
        S.of(context).get_picture,
      ),
      content: Container(
        height: 130.0,
        child: Column(
          children: <Widget>[
            Container(
              margin: EdgeInsets.only(bottom: 12.0),
              child: Text(
                S.of(context).get_picture_from,
                style: TextStyle(
                  fontSize: 15.0,
                  color: Colors.black26,
                ),
              ),
            ),
            Container(
              child: TextButton(
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    Icon(
                      Icons.photo_library,
                    ),
                    Container(
                      margin: EdgeInsets.only(left: 5.0),
                      child: Text(
                        S.of(context).gallery,
                      ),
                    ),
                  ],
                ),
                onPressed: () {
                  getPictureFromGallery2(context, imageId, onGotFile);
                },
              ),
            ),
            Container(
              child: TextButton(
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    Icon(
                      Icons.photo_camera,
                    ),
                    Container(
                      margin: EdgeInsets.only(left: 5.0),
                      child: Text(
                        S.of(context).camera,
                      ),
                    ),
                  ],
                ),
                onPressed: () {
                  getPictureFromCamera2(context, imageId, onGotFile);
                },
              ),
            )
          ],
        ),
      ),
    );
  }

  void getPictureFromGallery2(BuildContext context, int imageId, OnGotFile onGotFile) async {
    ImagePicker picker = ImagePicker();
    var image = await picker.pickImage(source: ImageSource.gallery);
    Navigator.of(context).pop();
    onGotFile(imageId, image.path);
  }

  void getPictureFromCamera2(BuildContext context, int imageId, OnGotFile onGotFile) async {
    ImagePicker picker = ImagePicker();
    var image = await picker.pickImage(source: ImageSource.camera);
    Navigator.of(context).pop();
    onGotFile(imageId, image.path);
  }

  Future<void> createTicket(BuildContext context, String msg, List<Map<String, dynamic>> images,
      OnSuccess onSuccess, OnError onError, {int id}) {
    var formData = FormData();
    formData.fields.add(MapEntry("msg", msg));
    formData.fields.add(MapEntry('id', id == null ? '0' : id.toString()));
    for (int i = 0; i < images.length; i++) {
      String imagePath = images[i]['path'];
      if (imagePath.isNotEmpty) {
        String imageName = basename(imagePath);
        formData.files.add(
          MapEntry(
            "files",
            MultipartFile.fromFileSync(imagePath, filename: imageName)
          )
        );
      }
    }
    HttpUtil.httpPost('create-new-ticket-app/', (response) {
      if (onSuccess != null) {
        onSuccess(response);
      }
    },
      isFormData: true,
      // body: null,
      formData: formData,
      sendProgress: (int sent, int total) {
        if (sent == total) {
          eventBus.fire(OnSubmitProgressEvent(false, 100.0));
        } else {
          eventBus.fire(OnSubmitProgressEvent(true, sent / total * 100.0));
        }
      },
      businessId: Constants.BUSINESS_ID,
    ).catchError((error) {
      if (onError != null) {
        onError(error);
      }
    });
  }

  Widget getNativePay(BuildContext context, Order order, PaymentPlatform paymentPlatform) {
    // Native (Apple/Google) pay removed with Stripe. Web uses e-Transfer.
    return SizedBox.shrink();
  }

  static void goPayment(BuildContext context, Order order,
      PaymentPlatform paymentPlatform, {
        bool googlePay=false,
        bool applePay=false,
      }) {
    switch(paymentPlatform.code) {
      case Constants.PAYMENT_METHOD_CODE_SQUARE:

        break;
      case Constants.PAYMENT_METHOD_CODE_CHASE:

        break;
      case Constants.PAYMENT_METHOD_CODE_PAYPAL:

        break;
      case Constants.PAYMENT_METHOD_CODE_OTT_ALIPAY:

        break;
      case Constants.PAYMENT_METHOD_CODE_OTT_WECHATPAY:

        break;
      case Constants.PAYMENT_METHOD_CODE_POD:

        break;
      case Constants.PAYMENT_METHOD_NATIVE_PAY:
        // Native (Apple/Google) pay removed with Stripe; route to e-Transfer.
        Navigator.pushReplacement(context, MaterialPageRoute(
            builder: (BuildContext context) {
              return ETransferPay(order: order);
            }
        ));
        break;
      case Constants.PAYMENT_METHOD_CODE_STRIPE:
        Navigator.pushReplacement(context, MaterialPageRoute(
            builder: (BuildContext context) {
              return ETransferPay(order: order);
            }
        ));
        break;
    }
  }

  static Future<Uint8List> getBytesFromAsset(String path, int width) async {
    ByteData data = await rootBundle.load(path);
    ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width);
    ui.FrameInfo fi = await codec.getNextFrame();
    return (await fi.image.toByteData(format: ui.ImageByteFormat.png)).buffer.asUint8List();
  }
}