import 'dart:async';
import 'dart:io';

import 'package:intl/intl.dart';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:fluttertoast/fluttertoast.dart';
import 'package:image/image.dart' as img;
import 'package:image_picker/image_picker.dart';

import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';

import 'package:mobdr/config/constant.dart';
import 'package:mobdr/service/shared_prefs.dart';
import 'package:mobdr/main.dart';
import 'package:mobdr/db/box_visit_photo.dart';
import 'package:mobdr/model/visit_model.dart';
import 'package:mobdr/ui/reusable/global_widget.dart';
import 'package:mobdr/ui/home/photo_camera.dart';
import 'package:mobdr/ui/visit/visit_photo_typology_detail.dart';
import 'package:mobdr/events.dart';

// TODO Il faut supprimer les possibles photos du répertoire cache !

extension FileNameExtension on File {
  String getFileName() {
    String fileName = path.split('/').last;
    return fileName;
  }
}

class VisitPhotoTypologyListPage extends StatefulWidget {
  final VisitModel pp_visitModel;
  final int pp_id_typologie;
  final String pp_libelle_typologie;

  VisitPhotoTypologyListPage(
      {required this.pp_visitModel,
      required this.pp_id_typologie,
      required this.pp_libelle_typologie});

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

class _VisitPhotoTypologyListPageState
    extends State<VisitPhotoTypologyListPage> {
  final _globalWidget = GlobalWidget();

  // initialize photos files list
  final List<File> _visitPhotoFiles = [];
  List<VisitPhoto> _visitPhotoData = [];

  Color _color1 = Color(0xff777777);
  Color _color2 = Color(0xFF515151);

  late int visitPhotoCount = 0;

  // _listKey is used for AnimatedList
  var _listKey = GlobalKey<AnimatedListState>();

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

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final double boxImageSize = (MediaQuery.of(context).size.width / 4);
    return Scaffold(
        appBar: AppBar(
          iconTheme: IconThemeData(
            color: Colors.black, //change your color here
          ),
          systemOverlayStyle: SystemUiOverlayStyle.dark,
          elevation: 0,
          title: Text(
            widget.pp_libelle_typologie,
            style: TextStyle(fontSize: 18, color: Colors.black),
          ),
          backgroundColor: Colors.white,
          actions: [
            GestureDetector(
                onTap: () {
                  Fluttertoast.showToast(
                      msg: 'Click message', toastLength: Toast.LENGTH_SHORT);
                },
                child: Icon(Icons.email, color: _color1)),
            IconButton(
                icon: _globalWidget.customNotifIcon(
                    count: 8,
                    notifColor: _color1,
                    notifSize: 24,
                    labelSize: 14),
                //icon: _globalWidget.customNotifIcon2(8, _color1),
                onPressed: () {
                  Fluttertoast.showToast(
                      msg: 'Click notification',
                      toastLength: Toast.LENGTH_SHORT);
                }),
          ],
        ),
        body: Column(children: [
          Flexible(
            child: AnimatedList(
              key: _listKey,
              initialItemCount: _visitPhotoData.length,
              physics: AlwaysScrollableScrollPhysics(),
              itemBuilder: (context, index, animation) {
                return _buildPhotolistCard(
                    _visitPhotoData[index], boxImageSize, animation, index);
              },
            ),
          ),
          Container(
            padding: EdgeInsets.all(12),
            decoration: BoxDecoration(
              color: Colors.white,
              boxShadow: [
                BoxShadow(
                  color: Colors.grey,
                  offset: Offset(0.0, 1.0), //(x,y)
                  blurRadius: 2.0,
                ),
              ],
            ),
            child: Row(
              children: [
                Container(
                  child: GestureDetector(
                    onTap: () {
                      ImportImageFromGallery();
                    },
                    child: ClipOval(
                      child: Container(
                          color: SOFT_BLUE,
                          padding: EdgeInsets.all(9),
                          child: Icon(Icons.photo_library,
                              color: Colors.white, size: 16)),
                    ),
                  ),
                ),
                SizedBox(
                  width: 10,
                ),
                Expanded(
                  child: GestureDetector(
                    onTap: () async {
                      // clear photoFiles list before taking photos
                      _visitPhotoFiles.clear();

                      // if we are not on a simulator
                      if (SharedPrefs().isSimulator == false) {
                        Route route = MaterialPageRoute(
                            builder: (context) =>
                                CameraPage(photoFiles: _visitPhotoFiles));
                        Navigator.push(context, route).then((val) {
                          // Restore the constraint before navigating away
                          // DO await here to avoid any other screen in
                          // landscape mode
                          SystemChrome.setPreferredOrientations([
                            DeviceOrientation.portraitUp,
                          ]);

                          // if the user has validated photos
                          if (val == true) {
                            savePhotos();
                          }
                        });
                      } else {
                        // simulates the taking of a photo
                        final File imageFile =
                            await copyImageFromAssetsToTemporaryDirectory();
                        _visitPhotoFiles.add(imageFile);
                        savePhotos();
                      }
                    },
                    child: Container(
                      alignment: Alignment.center,
                      padding: EdgeInsets.fromLTRB(12, 8, 12, 8),
                      margin: EdgeInsets.only(right: 8),
                      decoration: BoxDecoration(
                          color: Colors.white,
                          border: Border.all(width: 1, color: SOFT_BLUE),
                          borderRadius: BorderRadius.all(Radius.circular(
                                  10) //         <--- border radius here
                              )),
                      child: Text('Prendre des photos',
                          style: TextStyle(
                              color: SOFT_BLUE, fontWeight: FontWeight.bold)),
                    ),
                  ),
                ),
              ],
            ),
          )
        ]));
  }

  Widget _buildPhotolistCard(
      VisitPhoto photoData, boxImageSize, animation, index) {
    return SizeTransition(
      sizeFactor: animation,
      child: Container(
        margin: EdgeInsets.fromLTRB(12, 6, 12, 0),
        child: Card(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(10),
          ),
          elevation: 2,
          color: Colors.white,
          child: Container(
            margin: EdgeInsets.all(8),
            child: Column(
              children: [
                GestureDetector(
                  onTap: () {
                    Route route = MaterialPageRoute(
                        builder: (context) => VisitPhotoTypologyDetailPage(
                              pp_imageId: _visitPhotoData[index].id,
                              pp_visitModel: widget.pp_visitModel,
                              pp_image: _visitPhotoData[index].getImage(),
                              pp_id_typologie: widget.pp_id_typologie,
                            ));

                    Navigator.push(context, route).then((result) {
                      if (result['change_typologie']) {
                        // the photo must be removed
                        setState(() {
                          _visitPhotoData.removeAt(index);
                          _listKey = GlobalKey<AnimatedListState>();
                        });
                      } else {
                        setState(() {
                          _visitPhotoData[index].tags = result['tags'];
                          _visitPhotoData[index].photo_principale =
                              result['photo_principale'];
                          _visitPhotoData[index].photo_privee =
                              result['photo_privee'];
                        });
                      }
                    });
                  },
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      ClipRRect(
                        borderRadius: BorderRadius.all(Radius.circular(10)),
                        child: Image.file(File(photoData.getImage()),
                            fit: BoxFit.cover, height: 100, width: 150),
                      ),
                      SizedBox(
                        width: 10,
                      ),
                      Expanded(
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Container(
                              margin: EdgeInsets.only(top: 5),
                              child: Row(
                                children: [
                                  Text(
                                      DateFormat('dd/MM/yyyy HH:mm:ss')
                                          .format(photoData.date_photo),
                                      style: TextStyle(
                                          fontSize: 11, color: SOFT_GREY))
                                ],
                              ),
                            ),
                            Container(height: 8),
                            Text(
                              "Private : ${photoData.photo_privee == 1 ? 'Yes' : 'No'}",
                              style: TextStyle(fontSize: 13, color: _color2),
                              maxLines: 3,
                              overflow: TextOverflow.ellipsis,
                            ),
                            Container(
                              margin: EdgeInsets.only(top: 5),
                              child: Text(
                                  '${photoData.tags.isNotEmpty ? (photoData.tags.length > 53 ? '${photoData.tags.substring(0, 50)}...' : photoData.tags) : "notag"}',
                                  style: TextStyle(
                                      fontSize: 13,
                                      fontWeight: FontWeight.bold)),
                            ),
                            Container(height: 8),
                          ],
                        ),
                      )
                    ],
                  ),
                ),
                Container(
                  margin: EdgeInsets.only(top: 12),
                  child: Row(
                    children: [
                      GestureDetector(
                        behavior: HitTestBehavior.translucent,
                        onTap: () {
                          showPopupDeletePhoto(index, boxImageSize);
                        },
                        child: Container(
                          padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
                          height: 30,
                          decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(8),
                              border: Border.all(
                                  width: 1, color: Colors.grey[300]!)),
                          child: Icon(Icons.delete, color: _color1, size: 20),
                        ),
                      ),
                      SizedBox(
                        width: 8,
                      ),
                      Expanded(
                        child: (1 == 0) // (productData.stock == 0)
                            ? TextButton(
                                style: ButtonStyle(
                                  minimumSize:
                                      MaterialStateProperty.all(Size(0, 30)),
                                  backgroundColor:
                                      MaterialStateProperty.resolveWith<Color>(
                                    (Set<MaterialState> states) =>
                                        Colors.grey[300]!,
                                  ),
                                  overlayColor: MaterialStateProperty.all(
                                      Colors.transparent),
                                  shape: MaterialStateProperty.all(
                                      RoundedRectangleBorder(
                                    borderRadius: BorderRadius.circular(5.0),
                                  )),
                                ),
                                onPressed: null,
                                child: Text(
                                  'Out of Stock',
                                  style: TextStyle(
                                      color: Colors.grey[600],
                                      fontWeight: FontWeight.bold,
                                      fontSize: 13),
                                  textAlign: TextAlign.center,
                                ))
                            : OutlinedButton(
                                onPressed: () {
                                  Fluttertoast.showToast(
                                      msg:
                                          'Item has been added to Shopping Cart');
                                },
                                style: ButtonStyle(
                                    minimumSize:
                                        MaterialStateProperty.all(Size(0, 30)),
                                    overlayColor: MaterialStateProperty.all(
                                        Colors.transparent),
                                    shape: MaterialStateProperty.all(
                                        RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(5.0),
                                    )),
                                    side: MaterialStateProperty.all(
                                      BorderSide(color: SOFT_GREY, width: 1.0),
                                    )),
                                child: Text(
                                  'Copier dans galerie',
                                  style: TextStyle(
                                      color: SOFT_GREY,
                                      fontWeight: FontWeight.bold,
                                      fontSize: 13),
                                  textAlign: TextAlign.center,
                                )),
                      ),
                      SizedBox(
                        width: 8,
                      ),
                      GestureDetector(
                        behavior: HitTestBehavior.translucent,
                        onTap: () async {
                          await rotateAndReplaceImage(
                              File(_visitPhotoData[index].getImage()), 90);
                          setState(() {
                            _listKey = GlobalKey();
                          });
                          Fluttertoast.showToast(
                              msg: 'The image has been rotated');
                        },
                        child: Container(
                          padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
                          height: 30,
                          decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(8),
                              border: Border.all(
                                  width: 1, color: Colors.grey[300]!)),
                          child: Icon(Icons.rotate_right_rounded,
                              color: _color1, size: 20),
                        ),
                      ),
                      SizedBox(
                        width: 8,
                      ),
                      GestureDetector(
                        behavior: HitTestBehavior.translucent,
                        onTap: () async {
                          await rotateAndReplaceImage(
                              File(_visitPhotoData[index].getImage()), -90);
                          setState(() {
                            _listKey = GlobalKey();
                          });
                          Fluttertoast.showToast(
                              msg: 'The image has been rotated');
                        },
                        child: Container(
                          padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
                          height: 30,
                          decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(8),
                              border: Border.all(
                                  width: 1, color: Colors.grey[300]!)),
                          child: Icon(Icons.rotate_left_rounded,
                              color: _color1, size: 20),
                        ),
                      )
                    ],
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }

  void loadData() {
    _visitPhotoData = objectbox.getAllVisitTypologyPhotos(
        widget.pp_visitModel.id_visite, widget.pp_id_typologie);

    // number of photos of the visit
    visitPhotoCount =
        objectbox.getVisitPhotoCount(widget.pp_visitModel.id_visite);
  }

  /// Removes the image at the specified [imageURL] from the cache of the [NetworkImage] provider.
  /// Returns a boolean indicating whether the image was successfully evicted.
  Future<bool> evictImage(String imageURL) async {
    final NetworkImage provider = NetworkImage(imageURL);
    return await provider.evict();
  }

  /// Saves photos to the database and updates the widget with the new photos.
  ///
  void savePhotos() async {
    if (_visitPhotoFiles.length > 0) {
      final List<VisitPhoto> _listPhotos = [];

      for (var myTmpPhoto in _visitPhotoFiles) {
        /// move jpg file to photo directory
        final myPhoto = await moveFileFromTempToPhotosDir(myTmpPhoto);

        /// to insert into database
        _listPhotos.add(VisitPhoto(
            id_visite: widget.pp_visitModel.id_visite,
            id_photo_typologie: widget.pp_id_typologie,
            depuis_galerie: false,
            image_name: myPhoto.path.split('/').last));
      }

      /// insert photo(s) in database (async)
      final addedPhotos = await objectbox.addPhotos(_listPhotos);

      /// insert photo(s) in widget at the beginning (0)
      _visitPhotoData.insertAll(0, addedPhotos);

      /// if new photos are taken
      if (addedPhotos.length > 0) {
        visitPhotoCount += addedPhotos.length;
        // a global refresh event is sent
        eventBus.fire(VisitPhotoCountEvent(
            widget.pp_visitModel.id_visite, visitPhotoCount));
      }

      /// refresh widget
      setState(() {
        _listKey = GlobalKey();
      });
    }
  }

  /// Deletes the given file if it exists.
  ///
  /// Returns nothing.
  ///
  /// Throws an error if there was an issue deleting the file.
  Future<void> deleteFile(File file) async {
    try {
      if (await file.exists()) {
        await file.delete();
      }
    } catch (e) {
      // Error in getting access to the file.
      // todo toast
      print(e.toString());
    }
  }

  /// Shows an alert dialog to confirm the deletion of a photo from the visit and
  /// removes it from the list of photos. Also deletes the photo file from the
  /// database and local storage.
  ///
  /// Parameters:
  ///  - index : index of the photo in the list to be deleted.
  ///  - boxImageSize : size of the image to be displayed in the list.
  void showPopupDeletePhoto(index, boxImageSize) {
    // set up the buttons
    Widget cancelButton = TextButton(
        onPressed: () {
          Navigator.pop(context);
        },
        child: Text('No', style: TextStyle(color: SOFT_BLUE)));
    Widget continueButton = TextButton(
        onPressed: () {
          int removeIndex = index;
          var removedItem = _visitPhotoData.removeAt(removeIndex);

          // a global refresh event is sent
          visitPhotoCount -= 1;
          eventBus.fire(VisitPhotoCountEvent(
              widget.pp_visitModel.id_visite, visitPhotoCount));

          // delete file on database
          objectbox.delPhotoByName(removedItem.image_name);

          // if the photo is not from the gallery
          if (removedItem.depuis_galerie == false) {
            // delete file on local storage
            deleteFile(new File(removedItem.getImage()));
          }

          // This builder is just so that the animation has something
          // to work with before it disappears from view since the original
          // has already been deleted.
          AnimatedRemovedItemBuilder builder = (context, animation) {
            // A method to build the Card widget.
            return _buildPhotolistCard(
                removedItem, boxImageSize, animation, removeIndex);
          };
          _listKey.currentState!.removeItem(removeIndex, builder);

          Navigator.pop(context);

          Fluttertoast.showToast(
              msg: 'Photo has been deleted from your visit',
              toastLength: Toast.LENGTH_SHORT);
        },
        child: Text('Yes', style: TextStyle(color: SOFT_BLUE)));

    // set up the AlertDialog
    AlertDialog alert = AlertDialog(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10),
      ),
      title: Text(
        'Delete Photo',
        style: TextStyle(fontSize: 18),
      ),
      content: Text('Are you sure to delete this photo from your visit ?',
          style: TextStyle(fontSize: 13, color: _color1)),
      actions: [
        cancelButton,
        continueButton,
      ],
    );

    // show the dialog
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return alert;
      },
    );
  }

  // Moves a temporary file to the photos directory in the app's document directory.
  ///
  /// Returns a `File` object for the new file in the photos directory.
  ///
  /// Parameters:
  /// * `tempFile`: The temporary `File` object to move to the photos directory.
  ///
  /// Throws a `FileSystemException` if there is an error renaming the file.
  Future<File> moveFileFromTempToPhotosDir(File tempFile) async {
    // Set the new file path with the original file name
    final String newPath =
        '${SharedPrefs().photosDir}/${tempFile.path.split('/').last}';

    // Rename the file to move it to the documents directory
    await tempFile.rename(newPath);

    // Create and return a new File object for the new file
    return File(newPath);
  }

  /// Rotates the image file clockwise by the specified angle (in degrees) and overwrites the original file with the rotated image.
  ///
  /// Parameters:
  /// - `imageFile`: The image file to rotate and replace.
  /// - `angle`: The angle (in degrees) by which to rotate the image. Valid values are 90, 180, and 270.
  ///
  /// Throws an exception if there is an error in the rotation process.
  Future<void> rotateAndReplaceImage(File imageFile, int angle) async {
    // Read the image file into a Uint8List
    Uint8List bytes = await imageFile.readAsBytes();

    // Decode the bytes into an Image object using the image package
    img.Image? image = img.decodeImage(bytes);

    // Rotate the image clockwise by 90 degrees
    img.Image? rotatedImage = img.copyRotate(image!, angle: angle);

    // Encode the rotated image back into a Uint8List
    Uint8List rotatedBytes = img.encodePng(rotatedImage);

    // Overwrite the original file with the rotated image
    await imageFile.writeAsBytes(rotatedBytes);

    // remove the flutter cache image
    FileImage(imageFile).evict();
  }

  /// Copies the 'simulator.jpg' image file from the app's assets to a randomly named file in the app's temporary directory and returns the File object.
  /// The temporary file name will start with 'sim_'.
  Future<File> copyImageFromAssetsToTemporaryDirectory() async {
    final String randomName = 'sim_${DateTime.now().microsecondsSinceEpoch}';
    final Directory tempDir = await getTemporaryDirectory();
    final String tempPath = tempDir.path;
    final String assetPath = 'assets/images/simulator.jpeg';

    final ByteData data = await rootBundle.load(assetPath);
    final File tempFile = File('$tempPath/$randomName.jpeg');
    await tempFile.writeAsBytes(data.buffer.asUint8List(), flush: true);

    return tempFile;
  }

  Future<void> ImportImageFromGallery() async {
    try {
      // get images from gallery
      List<XFile>? images = await ImagePicker().pickMultiImage();

      // if images have been selected
      if (images.length > 0) {
        final List<VisitPhoto> _listPhotos = [];

        for (var image in images) {
          // to insert into database
          _listPhotos.add(VisitPhoto(
              id_visite: widget.pp_visitModel.id_visite,
              id_photo_typologie: widget.pp_id_typologie,
              depuis_galerie: true,
              image_name: image.path));
        }

        // insert photo(s) in database (async)
        final addedPhotos = await objectbox.addPhotos(_listPhotos);

        // insert photo(s) in widget at the beginning (0)
        _visitPhotoData.insertAll(0, addedPhotos);

        // if new photos are taken
        if (addedPhotos.length > 0) {
          visitPhotoCount += addedPhotos.length;
          // a global refresh event is sent
          eventBus.fire(VisitPhotoCountEvent(
              widget.pp_visitModel.id_visite, visitPhotoCount));
        }

        // refresh widget
        setState(() {
          _listKey = GlobalKey();
        });
      }
    } catch (e) {
      // Gestion de l'erreur
      print('Erreur lors de la sélection d\'images : $e');
    }
  }
}
