import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:path_provider/path_provider.dart';
import 'package:tangheem/exceptions/api_exception.dart';
import 'package:tangheem/ui/dialogs/loading_dialog.dart';
import 'package:http/http.dart' as http;
import 'colors.dart';

class Utils {
  static bool _isLoadingVisible = false;

  static bool get isLoading => _isLoadingVisible;

  static void showToast(String message) {
    Fluttertoast.showToast(msg: message, toastLength: Toast.LENGTH_LONG, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 1, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0);
  }

  static dynamic getNotNullValue(List<dynamic> list, int index) {
    try {
      return list[index];
    } catch (ex) {
      return null;
    }
  }

  static int stringToHex(String colorCode) {
    try {
      return int.parse(colorCode.replaceAll("#", "0xff"));
    } catch (ex) {
      return (0xff000000);
    }
  }

  static void showLoading(BuildContext context) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _isLoadingVisible = true;
      showDialog(
        context: context,
        barrierColor: ColorConsts.primaryBlack.withOpacity(0.5),
        builder: (BuildContext context) => LoadingDialog(),
      ).then((value) {
        _isLoadingVisible = false;
      });
    });
  }

  static void hideLoading(BuildContext context) {
    if (_isLoadingVisible) {
      _isLoadingVisible = false;
      Navigator.of(context).pop();
    }
    _isLoadingVisible = false;
  }

  static void handleException(dynamic exception, Function(String) onErrorMessage) {
    String errorMessage;
    if (exception is APIException) {
      if (exception.message == APIException.UNAUTHORIZED) {
        return;
      } else {
        var message = exception.error?.errorMessage;
        if (message == null) {
          message = exception.message;
        } else if (message == '"not authorized"') {
          message = "يرجى توثيق حسابك من خلال الرابط الذي تم إرساله إلى بريدك الإلكتروني";
        }
        errorMessage = message;
      }
    } else {
      errorMessage = APIException.UNKNOWN;
    }
    if (onErrorMessage != null) {
      onErrorMessage(errorMessage);
    } else {
      showToast(errorMessage);
    }
  }

  static Future<String> getStoragePath(String fileName) async {
    Directory storageDirectory;
    if (Platform.isAndroid) {
      storageDirectory = await getExternalStorageDirectory();
    } else if (Platform.isIOS) {
      storageDirectory = await getApplicationDocumentsDirectory();
    } else {
      return "";
    }

    String storagePath = storageDirectory.path;
    if (storagePath.contains("/Android/data")) {
      storagePath = storagePath.substring(0, storagePath.indexOf("/Android/data"));
    }

    if (Platform.isAndroid) {
      storagePath += "/Download/Tangheem/";
    } else {
      storagePath += "/PDFs/";
    }

    var d = Directory(storagePath);
    if (!d.existsSync()) {
      d.createSync(recursive: true);
    }
    storagePath += fileName;
    return storagePath;
  }

  static void downloadFile(String url, String path, {Function(bool) onResponse}) {
    print("url:$url");
    print("path:$path");
    var httpClient = http.Client();
    var request = http.Request('GET', Uri.parse(url));
    var response = httpClient.send(request);
    String dir = path;

    List<List<int>> chunks = [];
    int downloaded = 0;
    int lastVal;

    response.asStream().listen((http.StreamedResponse r) {
      r.stream.listen((List<int> chunk) {
        debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
        lastVal = (downloaded / r.contentLength * 100).toInt();

        chunks.add(chunk);
        downloaded += chunk.length;
      }, onDone: () async {
        debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
        if (lastVal == 0) {
          onResponse(false);
          return;
        }
        // Save the file
        File file = new File('$dir');
        final Uint8List bytes = Uint8List(r.contentLength);
        int offset = 0;
        for (List<int> chunk in chunks) {
          bytes.setRange(offset, offset + chunk.length, chunk);
          offset += chunk.length;
        }
        print("file writeAsBytes:${bytes.length}");
        await file.writeAsBytes(bytes);
        onResponse(true);
        return;
      }, onError: (ex) {
        debugPrint("onError:$ex");
        onResponse(false);
      }, cancelOnError: true);
    }).onError((ex) {
      debugPrint("onError:$ex");
      onResponse(false);
    });
  }

  void saveToPhoneStorage(String filePath) async {
    File file = File(filePath);
    Directory storageDirectory;
    if (Platform.isAndroid) {
      storageDirectory = await getExternalStorageDirectory();
    } else if (Platform.isIOS) {
      storageDirectory = await getApplicationDocumentsDirectory();
    } else {
      return;
    }

    String storagePath = storageDirectory.path;
    if (storagePath.contains("/Android/data")) {
      storagePath = storagePath.substring(0, storagePath.indexOf("/Android/data"));
    }

    if (Platform.isAndroid) {
      storagePath += "/Download/Tangheem/";
    } else {
      storagePath += "/Recording/";
    }

    var d = Directory(storagePath);
    if (!d.existsSync()) {
      d.createSync(recursive: true);
    }
    storagePath += "Tangheem${DateTime.now().millisecondsSinceEpoch}.mp3";
    print("storagePath:$storagePath");
    await file.copy(storagePath);
    Utils.showToast("تم التنزيل");
  }

  static void downloadFileAboveAndroid32(String url, String path, {Function(List<int> bytes) onResponse}) {
    print("url:$url");
    print("path:$path");
    var httpClient = http.Client();
    var request = http.Request('GET', Uri.parse(url));
    var response = httpClient.send(request);
    String dir = path;

    List<List<int>> chunks = [];
    int downloaded = 0;
    int lastVal;

    response.asStream().listen((http.StreamedResponse r) {
      r.stream.listen((List<int> chunk) {
        debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
        lastVal = (downloaded / r.contentLength * 100).toInt();

        chunks.add(chunk);
        downloaded += chunk.length;
      }, onDone: () async {
        debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
        if (lastVal == 0) {
          onResponse([]);
          return;
        }
        final Uint8List bytes = Uint8List(r.contentLength);
        int offset = 0;
        for (List<int> chunk in chunks) {
          bytes.setRange(offset, offset + chunk.length, chunk);
          offset += chunk.length;
        }
        onResponse(bytes);
        return;
      }, onError: (ex) {
        debugPrint("onError:$ex");
        onResponse([]);
      }, cancelOnError: true);
    }).onError((ex) {
      debugPrint("onError:$ex");
      onResponse([]);
    });
  }

}
