import 'dart:io';

import 'package:camera/camera.dart';
import 'package:farm_tpf/main.dart';
import 'package:farm_tpf/presentation/custom_widgets/widget_utils.dart';
// import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:video_player/video_player.dart';
import 'package:path_provider/path_provider.dart';

class CameraHelper extends StatefulWidget {
  @override
  _CameraHelperState createState() => _CameraHelperState();
}

/// Returns a suitable camera icon for [direction].
IconData getCameraLensIcon(CameraLensDirection direction) {
  switch (direction) {
    case CameraLensDirection.back:
      return Icons.camera_rear;
    case CameraLensDirection.front:
      return Icons.camera_front;
    case CameraLensDirection.external:
      return Icons.camera;
  }
  throw ArgumentError('Unknown lens direction');
}

void logError(String code, String message) => print('Error: $code\nError Message: $message');

class _CameraHelperState extends State<CameraHelper> with WidgetsBindingObserver {
  late CameraController controller;
  String? imagePath;
  String? videoPath;
  VideoPlayerController? videoController;
  VoidCallback? videoPlayerListener;
  bool enableAudio = true;
  int indexCamera = 0;
  List<CameraDescription> cameras = [];

  @override
  void initState() {
    super.initState();
    controller = CameraController(cameras[indexCamera], ResolutionPreset.medium);
    controller.initialize().then((_) {
      if (!mounted) {
        return;
      }
      setState(() {});
    });
    WidgetsBinding.instance?.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance?.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    // App state changed before we got the chance to initialize.
    if (controller == null || !controller.value.isInitialized) {
      return;
    }
    if (state == AppLifecycleState.inactive) {
      controller?.dispose();
    } else if (state == AppLifecycleState.resumed) {
      if (controller != null) {
        onNewCameraSelected(controller.description);
      }
    }
  }

  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      body: SafeArea(
        top: false,
        bottom: false,
        child: Column(
          children: <Widget>[
            Expanded(
              child: Container(
                child: Padding(
                  padding: const EdgeInsets.all(1.0),
                  child: Center(
                    child: _cameraPreviewWidget(),
                  ),
                ),
                decoration: BoxDecoration(
                  color: Colors.black,
                  border: Border.all(
                    color: controller != null && controller.value.isRecordingVideo ? Colors.redAccent : Colors.grey,
                    width: controller != null && controller.value.isRecordingVideo ? 1.0 : 0.0,
                  ),
                ),
              ),
            ),
            _captureControlRowWidget(),
          ],
        ),
      ),
    );
  }

  /// Display the preview from the camera (or a message if the preview is not available).
  Widget _cameraPreviewWidget() {
    if (controller == null || !controller.value.isInitialized) {
      return const Text(
        'Đang mở camera ....',
        style: TextStyle(
          color: Colors.white,
          fontSize: 18.0,
          fontWeight: FontWeight.w900,
        ),
      );
    } else {
      return AspectRatio(
        aspectRatio: controller.value.aspectRatio,
        child: CameraPreview(controller),
      );
    }
  }

  /// Display the control bar with buttons to take pictures and record videos.
  Widget _captureControlRowWidget() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      mainAxisSize: MainAxisSize.max,
      children: <Widget>[
        IconButton(
            icon: const Icon(Icons.arrow_back),
            onPressed: () {
              Get.back();
            }),
        _cameraTogglesRowWidget(),
        IconButton(
          icon: const Icon(
            Icons.camera_alt,
            size: 30,
          ),
          color: Colors.blue,
          onPressed: controller != null && controller.value.isInitialized && !controller.value.isRecordingVideo ? onTakePictureButtonPressed : null,
        ),
        IconButton(
          icon: const Icon(Icons.videocam, size: 35),
          color: Colors.blue,
          onPressed: controller != null && controller.value.isInitialized && !controller.value.isRecordingVideo ? onVideoRecordButtonPressed : null,
        ),
        IconButton(
          icon: controller != null && controller.value.isRecordingPaused ? const Icon(Icons.play_arrow) : const Icon(Icons.pause),
          color: Colors.blue,
          onPressed: controller != null && controller.value.isInitialized && controller.value.isRecordingVideo
              ? (controller != null && controller.value.isRecordingPaused ? onResumeButtonPressed : onPauseButtonPressed)
              : null,
        ),
        IconButton(
          icon: const Icon(Icons.stop),
          color: Colors.red,
          onPressed: controller != null && controller.value.isInitialized && controller.value.isRecordingVideo ? onStopButtonPressed : null,
        )
      ],
    );
  }

  /// Display a row of toggle to select the camera (or a message if no camera is available).
  Widget _cameraTogglesRowWidget() {
    if (cameras.isEmpty) {
      return const Text('Không có camera');
    } else {
      var disableSwitch = controller != null && controller.value.isRecordingVideo;
      if (indexCamera == cameras.length - 1) {
        indexCamera = 0;
      } else {
        indexCamera++;
      }
      return IconButton(
          icon: const Icon(
            Icons.switch_camera,
            color: Colors.green,
          ),
          onPressed: disableSwitch == true
              ? null
              : () {
                  onNewCameraSelected(cameras[indexCamera]);
                });
    }
  }

  String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();

  void showInSnackBar(String message) {
    Utils.showSnackBarError(message: message);
  }

  void onNewCameraSelected(CameraDescription cameraDescription) async {
    if (controller != null) {
      await controller.dispose();
    }
    controller = CameraController(
      cameraDescription,
      ResolutionPreset.medium,
      enableAudio: enableAudio,
    );

    // If the controller is updated then update the UI.
    controller.addListener(() {
      if (mounted) setState(() {});
      if (controller.value.hasError) {
        showInSnackBar('Lỗi camera: ${controller.value.errorDescription}');
      }
    });

    try {
      await controller.initialize();
    } on CameraException catch (e) {
      _showCameraException(e);
    }

    if (mounted) {
      setState(() {});
    }
  }

  void onTakePictureButtonPressed() {
    takePicture().then((String filePath) {
      if (mounted) {
        setState(() {
          imagePath = filePath;
          videoController?.dispose();
          // videoController = null;
        });
        if (filePath != null) {
          print('Picture saved to $filePath');
          Get.back(result: [filePath, false]);
        }
      }
    });
  }

  void onVideoRecordButtonPressed() {
    startVideoRecording().then((String filePath) {
      if (mounted) setState(() {});
      if (filePath != null) {
        print('Saving video to $filePath');
      }
    });
  }

  void onStopButtonPressed() {
    stopVideoRecording().then((_) {
      if (mounted) setState(() {});
      {
        print('Video recorded to: $videoPath');
        Get.back(result: [videoPath, true]);
      }
    });
  }

  void onPauseButtonPressed() {
    pauseVideoRecording().then((_) {
      if (mounted) setState(() {});
      print('Video recording paused');
    });
  }

  void onResumeButtonPressed() {
    resumeVideoRecording().then((_) {
      if (mounted) setState(() {});
      print('Video recording resumed');
    });
  }

  Future<String> startVideoRecording() async {
    if (!controller.value.isInitialized) {
      showInSnackBar('Vui lòng chọn camera');
      // return null;
    }

    final Directory extDir = await getApplicationDocumentsDirectory();
    final dirPath = '${extDir.path}/Movies/tpf';
    await Directory(dirPath).create(recursive: true);
    final filePath = '$dirPath/${timestamp()}.mp4';

    if (controller.value.isRecordingVideo) {
      // A recording is already started, do nothing.
      // return null;
    }

    try {
      videoPath = filePath;
      // await controller.startVideoRecording(filePath);
    } on CameraException catch (e) {
      _showCameraException(e);
      // return null;
    }
    return filePath;
  }

  Future<void> stopVideoRecording() async {
    if (!controller.value.isRecordingVideo) {
      return null;
    }

    try {
      await controller.stopVideoRecording();
    } on CameraException catch (e) {
      _showCameraException(e);
      return null;
    }
  }

  Future<void> pauseVideoRecording() async {
    if (!controller.value.isRecordingVideo) {
      return null;
    }

    try {
      await controller.pauseVideoRecording();
    } on CameraException catch (e) {
      _showCameraException(e);
      rethrow;
    }
  }

  Future<void> resumeVideoRecording() async {
    if (!controller.value.isRecordingVideo) {
      return null;
    }

    try {
      await controller.resumeVideoRecording();
    } on CameraException catch (e) {
      _showCameraException(e);
      rethrow;
    }
  }

  Future<String> takePicture() async {
    if (!controller.value.isInitialized) {
      showInSnackBar('Vui lòng chọn camera');
      // return null;
    }
    final Directory extDir = await getApplicationDocumentsDirectory();
    final dirPath = '${extDir.path}/Pictures/tpf';
    await Directory(dirPath).create(recursive: true);
    final filePath = '$dirPath/${timestamp()}.jpg';

    if (controller.value.isTakingPicture) {
      // A capture is already pending, do nothing.
      // return null;
    }

    try {
      // await controller.takePicture(filePath);
    } on CameraException catch (e) {
      _showCameraException(e);
      // return null;
    }
    return filePath;
  }

  void _showCameraException(CameraException e) {
    // logError(e.code, e.description);
    showInSnackBar('Lỗi: ${e.code}\n${e.description}');
  }
}
