import 'dart:async';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/shared/utils/dialog_util.dart';
import 'package:hub/shared/utils/limited_text_size.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mime_type/mime_type.dart';

import 'flutter_flow_theme.dart';
import 'flutter_flow_util.dart';

const allowedFormats = {'image/png', 'image/jpeg'};

class SelectedFile {
  const SelectedFile({
    this.storagePath = '',
    this.filePath,
    required this.bytes,
    this.dimensions,
    this.blurHash,
  });
  final String storagePath;
  final String? filePath;
  final Uint8List bytes;
  final MediaDimensions? dimensions;
  final String? blurHash;
}

class MediaDimensions {
  const MediaDimensions({
    this.height,
    this.width,
  });
  final double? height;
  final double? width;
}

enum MediaSource {
  photoGallery,
  videoGallery,
  camera,
}

Future<List<SelectedFile>?> selectMediaWithSourceBottomSheetandFaceDetection({
  required BuildContext context,
  String? storageFolderPath,
  double? maxWidth,
  double? maxHeight,
  int? imageQuality,
  required bool allowPhoto,
  bool allowVideo = false,
  String pickerFontFamily = 'Roboto',
  // Color textColor = const Color(0xFF111417),
  // Color backgroundColor = const Color(0xFFF5F5F5),
  bool includeDimensions = false,
  bool includeBlurHash = false,
}) async {
  final faceDetector = FaceDetector(
    options: FaceDetectorOptions(
      enableContours: true,
      enableLandmarks: true,
    ),
  );
  createUploadMediaListTile(
          String label, MediaSource mediaSource, IconData icon) =>
      ListTile(
        title: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(icon, color: FlutterFlowTheme.of(context).primaryText),
            const SizedBox(width: 5),
            Text(
              label,
              textAlign: TextAlign.center,
              style: GoogleFonts.getFont(
                pickerFontFamily,
                color: FlutterFlowTheme.of(context).primaryText,
                fontWeight: FontWeight.w600,
                fontSize: 12,
              ),
            ),
          ],
        ),
        tileColor: FlutterFlowTheme.of(context).primaryBackground,
        dense: false,
        onTap: () => context.pop(mediaSource),
      );
  final mediaSource = await showModalBottomSheet<MediaSource>(
      context: context,
      backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
      builder: (context) {
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            if (!kIsWeb) ...[
              Container(
                margin: const EdgeInsets.only(top: 10),
                width: 40,
                height: 5,
                decoration: BoxDecoration(
                  color: Colors.grey[300],
                  borderRadius: BorderRadius.circular(10),
                ),
              ),
              Padding(
                padding: const EdgeInsets.fromLTRB(0, 8, 0, 0),
                child: ListTile(
                  title: Text(
                    FFLocalizations.of(context).getVariableText(
                        ptText: "Escolha uma das opções",
                        enText: "Choose one of the options"),
                    textAlign: TextAlign.center,
                    style: GoogleFonts.getFont(
                      pickerFontFamily,
                      color: FlutterFlowTheme.of(context)
                          .primaryText
                          .withOpacity(0.65),
                      fontWeight: FontWeight.w500,
                      fontSize: 14,
                    ),
                  ),
                  tileColor: FlutterFlowTheme.of(context).primaryBackground,
                  dense: true,
                ),
              ),
            ],
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                if (allowPhoto && allowVideo) ...[
                  Expanded(
                    child: createUploadMediaListTile(
                        FFLocalizations.of(context).getVariableText(
                            ptText: "Galeria (Foto)",
                            enText: "Gallery (Photo)"),
                        MediaSource.photoGallery,
                        Icons.camera),
                  ),
                  Expanded(
                    child: createUploadMediaListTile(
                        FFLocalizations.of(context).getVariableText(
                            ptText: "Galeria (Video)",
                            enText: "Gallery (Video)"),
                        MediaSource.videoGallery,
                        Icons.videocam),
                  )
                ] else if (allowPhoto)
                  Expanded(
                      child: createUploadMediaListTile(
                          FFLocalizations.of(context).getVariableText(
                              ptText: "Galeria", enText: "Gallery"),
                          MediaSource.photoGallery,
                          Icons.photo))
                else
                  Expanded(
                    child: createUploadMediaListTile(
                        FFLocalizations.of(context).getVariableText(
                            ptText: "Galeria", enText: "Gallery"),
                        MediaSource.videoGallery,
                        Icons.videocam),
                  ),
                if (!kIsWeb) ...[
                  Expanded(
                    child: createUploadMediaListTile(
                        FFLocalizations.of(context).getVariableText(
                            ptText: "Camera", enText: "Camera"),
                        MediaSource.camera,
                        Icons.camera_alt),
                  )
                ],
              ],
            ),
            const SizedBox(height: 15),
          ],
        );
      });
  if (mediaSource == null) {
    return null;
  }
  final selectedMedia = await selectMedia(
    storageFolderPath: storageFolderPath,
    maxWidth: maxWidth,
    maxHeight: maxHeight,
    imageQuality: imageQuality,
    isVideo: mediaSource == MediaSource.videoGallery ||
        (mediaSource == MediaSource.camera && allowVideo && !allowPhoto),
    mediaSource: mediaSource,
    includeDimensions: includeDimensions,
    includeBlurHash: includeBlurHash,
  );

  if (selectedMedia == null || selectedMedia.isEmpty) {
    return null;
  }

  // Verifique se há faces na imagem
  for (final media in selectedMedia) {
    final inputImage = InputImage.fromFilePath(media.filePath!);
    final faces = await faceDetector.processImage(inputImage);
    if (faces.isEmpty) {
      final String message = FFLocalizations.of(context).getVariableText(
          ptText: "Nenhuma face detectada na imagem",
          enText: "No face detected in the image");
      await DialogUtil.error(context, message);
      return null;
    }
    if (faces.length > 1) {
      final String message = FFLocalizations.of(context).getVariableText(
          ptText: "Mais de uma face detectada na imagem",
          enText: "More than one face detected in the image");
      await DialogUtil.error(context, message);
      return null;
    }
  }

  return selectedMedia;
}

Future<List<SelectedFile>?> selectMediaWithSourceBottomSheet({
  required BuildContext context,
  String? storageFolderPath,
  double? maxWidth,
  double? maxHeight,
  int? imageQuality,
  required bool allowPhoto,
  bool allowVideo = false,
  String pickerFontFamily = 'Roboto',
  // Color textColor = const Color(0xFF111417),
  // Color backgroundColor = const Color(0xFFF5F5F5),
  bool includeDimensions = false,
  bool includeBlurHash = false,
}) async {
  createUploadMediaListTile(
          String label, MediaSource mediaSource, IconData icon) =>
      ListTile(
        title: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(icon, color: FlutterFlowTheme.of(context).primaryText),
            const SizedBox(width: 5),
            Text(
              label,
              textAlign: TextAlign.center,
              style: GoogleFonts.getFont(
                pickerFontFamily,
                color: FlutterFlowTheme.of(context).primaryText,
                fontWeight: FontWeight.w600,
                fontSize: 12,
              ),
            ),
          ],
        ),
        tileColor: FlutterFlowTheme.of(context).primaryBackground,
        dense: false,
        onTap: () => context.pop(mediaSource),
        // Navigator.pop(context,mediaSource,),
      );
  final mediaSource = await showModalBottomSheet<MediaSource>(
      context: context,
      backgroundColor: FlutterFlowTheme.of(context).primaryBackground,
      builder: (context) {
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            if (!kIsWeb) ...[
              Container(
                margin: const EdgeInsets.only(top: 10),
                width: 40,
                height: 5,
                decoration: BoxDecoration(
                  color: Colors.grey[300],
                  borderRadius: BorderRadius.circular(10),
                ),
              ),
              Padding(
                padding: const EdgeInsets.fromLTRB(0, 8, 0, 0),
                child: ListTile(
                  title: Text(
                    FFLocalizations.of(context).getVariableText(
                        ptText: "Escolha uma das opções",
                        enText: "Choose one of the options"),
                    textAlign: TextAlign.center,
                    style: GoogleFonts.getFont(
                      pickerFontFamily,
                      color: FlutterFlowTheme.of(context)
                          .primaryText
                          .withOpacity(0.65),
                      fontWeight: FontWeight.w500,
                      fontSize: 14,
                    ),
                  ),
                  tileColor: FlutterFlowTheme.of(context).primaryBackground,
                  dense: true,
                ),
              ),
            ],
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                if (allowPhoto && allowVideo) ...[
                  Expanded(
                    child: createUploadMediaListTile(
                        FFLocalizations.of(context).getVariableText(
                            ptText: "Galeria (Foto)",
                            enText: "Gallery (Photo)"),
                        MediaSource.photoGallery,
                        Icons.camera),
                  ),
                  Expanded(
                    child: createUploadMediaListTile(
                        FFLocalizations.of(context).getVariableText(
                            ptText: "Galeria (Video)",
                            enText: "Gallery (Video)"),
                        MediaSource.videoGallery,
                        Icons.videocam),
                  )
                ] else if (allowPhoto)
                  Expanded(
                      child: createUploadMediaListTile(
                          FFLocalizations.of(context).getVariableText(
                              ptText: "Galeria", enText: "Gallery"),
                          MediaSource.photoGallery,
                          Icons.photo))
                else
                  Expanded(
                    child: createUploadMediaListTile(
                        FFLocalizations.of(context).getVariableText(
                            ptText: "Galeria", enText: "Gallery"),
                        MediaSource.videoGallery,
                        Icons.videocam),
                  ),
                if (!kIsWeb) ...[
                  Expanded(
                    child: createUploadMediaListTile(
                        FFLocalizations.of(context).getVariableText(
                            ptText: "Camera", enText: "Camera"),
                        MediaSource.camera,
                        Icons.camera_alt),
                  )
                ],
              ],
            ),
            const SizedBox(height: 15),
          ],
        );
      });
  if (mediaSource == null) {
    return null;
  }
  return selectMedia(
    storageFolderPath: storageFolderPath,
    maxWidth: maxWidth,
    maxHeight: maxHeight,
    imageQuality: imageQuality,
    isVideo: mediaSource == MediaSource.videoGallery ||
        (mediaSource == MediaSource.camera && allowVideo && !allowPhoto),
    mediaSource: mediaSource,
    includeDimensions: includeDimensions,
    includeBlurHash: includeBlurHash,
  );
}

Future<List<SelectedFile>?> selectMedia({
  String? storageFolderPath,
  double? maxWidth,
  double? maxHeight,
  int? imageQuality,
  bool isVideo = false,
  MediaSource mediaSource = MediaSource.camera,
  bool multiImage = false,
  bool includeDimensions = false,
  bool includeBlurHash = false,
}) async {
  final picker = ImagePicker();

  if (multiImage) {
    final pickedMediaFuture = picker.pickMultiImage(
      maxWidth: maxWidth,
      maxHeight: maxHeight,
      imageQuality: imageQuality,
    );
    final pickedMedia = await pickedMediaFuture;
    if (pickedMedia.isEmpty) {
      return null;
    }
    return Future.wait(pickedMedia.asMap().entries.map((e) async {
      final index = e.key;
      final media = e.value;
      final mediaBytes = await media.readAsBytes();
      final path = _getStoragePath(storageFolderPath, media.name, false, index);
      final dimensions = includeDimensions
          ? isVideo
              ? _getVideoDimensions(media.path)
              : _getImageDimensions(mediaBytes)
          : null;

      return SelectedFile(
        storagePath: path,
        filePath: media.path,
        bytes: mediaBytes,
        dimensions: await dimensions,
      );
    }));
  }

  final source = mediaSource == MediaSource.camera
      ? ImageSource.camera
      : ImageSource.gallery;
  final pickedMediaFuture = isVideo
      ? picker.pickVideo(source: source)
      : picker.pickImage(
          maxWidth: maxWidth,
          maxHeight: maxHeight,
          imageQuality: imageQuality,
          source: source,
        );
  final pickedMedia = await pickedMediaFuture;
  final mediaBytes = await pickedMedia?.readAsBytes();
  if (mediaBytes == null) {
    return null;
  }
  final path = _getStoragePath(storageFolderPath, pickedMedia!.name, isVideo);
  final dimensions = includeDimensions
      ? isVideo
          ? _getVideoDimensions(pickedMedia.path)
          : _getImageDimensions(mediaBytes)
      : null;

  return [
    SelectedFile(
      storagePath: path,
      filePath: pickedMedia.path,
      bytes: mediaBytes,
      dimensions: await dimensions,
    ),
  ];
}

bool validateFileFormat(String filePath, BuildContext context) {
  if (allowedFormats.contains(mime(filePath))) {
    return true;
  }
  ScaffoldMessenger.of(context)
    ..hideCurrentSnackBar()
    ..showSnackBar(SnackBar(
      content: Text('Invalid file format: ${mime(filePath)}'),
    ));
  return false;
}

Future<SelectedFile?> selectFile({
  String? storageFolderPath,
  List<String>? allowedExtensions,
}) =>
    selectFiles(
      storageFolderPath: storageFolderPath,
      allowedExtensions: allowedExtensions,
      multiFile: false,
    ).then((value) => value?.first);

Future<List<SelectedFile>?> selectFiles({
  String? storageFolderPath,
  List<String>? allowedExtensions,
  bool multiFile = false,
}) async {
  final pickedFiles = await FilePicker.platform.pickFiles(
    type: allowedExtensions != null ? FileType.custom : FileType.any,
    allowedExtensions: allowedExtensions,
    withData: true,
    allowMultiple: multiFile,
  );
  if (pickedFiles == null || pickedFiles.files.isEmpty) {
    return null;
  }
  if (multiFile) {
    return Future.wait(pickedFiles.files.asMap().entries.map((e) async {
      final index = e.key;
      final file = e.value;
      final storagePath =
          _getStoragePath(storageFolderPath, file.name, false, index);
      return SelectedFile(
        storagePath: storagePath,
        filePath: isWeb ? null : file.path,
        bytes: file.bytes!,
      );
    }));
  }
  final file = pickedFiles.files.first;
  if (file.bytes == null) {
    return null;
  }
  final storagePath = _getStoragePath(storageFolderPath, file.name, false);
  return [
    SelectedFile(
      storagePath: storagePath,
      filePath: isWeb ? null : file.path,
      bytes: file.bytes!,
    )
  ];
}

List<SelectedFile> selectedFilesFromUploadedFiles(
  List<FFUploadedFile> uploadedFiles, {
  String? storageFolderPath,
  bool isMultiData = false,
}) =>
    uploadedFiles.asMap().entries.map(
      (entry) {
        final index = entry.key;
        final file = entry.value;
        return SelectedFile(
            storagePath: _getStoragePath(
              storageFolderPath,
              file.name!,
              false,
              isMultiData ? index : null,
            ),
            bytes: file.bytes!);
      },
    ).toList();

Future<MediaDimensions> _getImageDimensions(Uint8List mediaBytes) async {
  final image = await decodeImageFromList(mediaBytes);
  return MediaDimensions(
    width: image.width.toDouble(),
    height: image.height.toDouble(),
  );
}

Future<MediaDimensions> _getVideoDimensions(String path) async {
  // final VideoPlayerController videoPlayerController =
  //     VideoPlayerController.asset(path);
  // await videoPlayerController.initialize();
  // final size = videoPlayerController.value.size;
  //mock
  final size = const Size(1920, 1080);
  return MediaDimensions(width: size.width, height: size.height);
}

String _getStoragePath(
  String? pathPrefix,
  String filePath,
  bool isVideo, [
  int? index,
]) {
  pathPrefix = _removeTrailingSlash(pathPrefix);
  final timestamp = DateTime.now().microsecondsSinceEpoch;
  // Workaround fixed by https://github.com/flutter/plugins/pull/3685
  // (not yet in stable).
  final ext = isVideo ? 'mp4' : filePath.split('.').last;
  final indexStr = index != null ? '_$index' : '';
  return '$pathPrefix/$timestamp$indexStr.$ext';
}

String getSignatureStoragePath([String? pathPrefix]) {
  pathPrefix = _removeTrailingSlash(pathPrefix);
  final timestamp = DateTime.now().microsecondsSinceEpoch;
  return '$pathPrefix/signature_$timestamp.png';
}

void showUploadMessage(
  BuildContext context,
  String message, {
  bool showLoading = false,
}) {
  ScaffoldMessenger.of(context)
    ..hideCurrentSnackBar()
    ..showSnackBar(
      SnackBar(
        content: Row(
          children: [
            if (showLoading)
              Padding(
                padding: const EdgeInsetsDirectional.only(end: 10.0),
                child: CircularProgressIndicator(
                  valueColor: Theme.of(context).brightness == Brightness.dark
                      ? AlwaysStoppedAnimation<Color>(
                          FlutterFlowTheme.of(context).info)
                      : null,
                ),
              ),
            Text(message,
                style: TextStyle(
                  color: FlutterFlowTheme.of(context).primaryText,
                  fontSize: LimitedFontSizeUtil.getBodyFontSize(context),
                )),
          ],
        ),
        backgroundColor: FlutterFlowTheme.of(context).primary,
        shape: const RoundedRectangleBorder(
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(15),
            topRight: Radius.circular(15),
          ),
        ),
        duration:
            showLoading ? const Duration(days: 1) : const Duration(seconds: 4),
      ),
    );
}

String? _removeTrailingSlash(String? path) => path != null && path.endsWith('/')
    ? path.substring(0, path.length - 1)
    : path;
