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

import 'package:camera/camera.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:path_provider/path_provider.dart' as path_provider;
import 'package:image/image.dart' as resizeImage;

abstract class CameraEvent{}

class InitializeCamera extends CameraEvent{
  String defaultCamera;
  bool absensi;
  InitializeCamera(this.defaultCamera, this.absensi);
}

class ChangeCamera extends CameraEvent{}

class TakePicture extends CameraEvent{}

abstract class CameraState{}

class InitializeCameraProgress extends CameraState{}

class InitializeCameraSuccess extends CameraState{
  CameraController? controller;
  InitializeCameraSuccess(this.controller);
}

class TakePictureSuccess extends CameraState{
  File file;
  int? cameraId;
  TakePictureSuccess(this.file, this.cameraId);
}

class CameraBloc extends Bloc<CameraEvent, CameraState>{
  late List<CameraDescription> cameras;
  CameraController? controller;
  late XFile file;
  int? cameraId;
  bool? absensi;

  CameraBloc(CameraState initialState) : super(initialState);

  @override
  Stream<CameraState> mapEventToState(CameraEvent event) async*{
    // TODO: implement mapEventToState
    if(event is InitializeCamera){
      yield InitializeCameraProgress();
      cameraId = 1;
      if(event.defaultCamera=='front') cameraId = 1;
      else if(event.defaultCamera=='back') cameraId = 0;
      cameras = await availableCameras();
      controller = new CameraController(cameras[cameraId!], ResolutionPreset.high, enableAudio: false);
      await controller!.initialize();
      await Future.delayed(Duration(milliseconds: 500));
      yield InitializeCameraSuccess(controller);
    }
    else if(event is ChangeCamera){
      yield InitializeCameraProgress();
      if(cameraId==1) {
        cameraId=0;
        controller = new CameraController(cameras[cameraId!], ResolutionPreset.high, enableAudio: false);
        await controller!.initialize();
        await controller!.setFlashMode(FlashMode.off);
        await controller!.setFocusMode(FocusMode.auto);
      }
      else {
        cameraId = 1;
        controller = new CameraController(cameras[cameraId!], ResolutionPreset.high, enableAudio: false);
        await controller!.initialize();
        await controller!.setFocusMode(FocusMode.auto);
      }
      // print("CAMERA ID : $cameraId");
      await Future.delayed(Duration(milliseconds: 500));
      yield InitializeCameraSuccess(controller);
    }
    else if(event is TakePicture){
      yield InitializeCameraProgress();
      if (!controller!.value.isInitialized) {
        // print('Error: select a camera first.');
      }

      if (!controller!.value.isTakingPicture) {

        try {
          file = await controller!.takePicture();
          // print("file path : ${file.path}");

          /*if(controller.description.lensDirection==CameraLensDirection.front){
            await _flutterFFmpeg.execute("-y -i " +
                file.path +
                " -filter:v \"hflip\" " +
                file.path);
            print('flipped');
          }*/
          // print('Picture saved to ${file.path}');
          final dir = await path_provider.getTemporaryDirectory();
          File fileCompressed = File(file.path);
          resizeImage.Image? imageNew = resizeImage.decodeImage(fileCompressed.readAsBytesSync());
          // resizeImage.Image? thumbnail = resizeImage.copyResize(imageNew!, height: absensi==true?800:400);
          resizeImage.Image? thumbnail = resizeImage.copyResize(imageNew!, width: absensi==true?400:400);
          fileCompressed = new File(file.path)
            ..writeAsBytesSync(resizeImage.encodePng(thumbnail));
          fileCompressed = await testCompressAndGetFile(File(file.path), "${dir.absolute.path}/${DateTime.now()}.jpg");
          yield TakePictureSuccess(fileCompressed, cameraId);

        } on CameraException catch (e) {
          debugPrint('ERROR $e');
        }
      }
      else debugPrint('ERROR');
    }

  }

  Future<File> testCompressAndGetFile(File file, String targetPath) async {
    final result = await FlutterImageCompress.compressAndGetFile(
      file.absolute.path,
      targetPath,
      quality: 75,
    );

    if (result == null) {
      throw Exception('Compression failed');
    }

    print(file.lengthSync());

    // Convert XFile to File
    return File(result.path);
  }

}