import { Injectable } from '@angular/core';
import { Camera, CameraPermissionType, CameraResultType, CameraSource, GalleryImageOptions, ImageOptions } from '@capacitor/camera';
import { Filesystem } from '@capacitor/filesystem';
import { Crop } from '@ionic-native/crop/ngx';
import { ActionSheetController, Platform } from '@ionic/angular';
import { AlertService } from './alert.service';

@Injectable({
  providedIn: 'root'
})
export class CameraGalleryService {
  submitted = Boolean(false);
  constructor(
    protected actionSheetController: ActionSheetController,
    protected platform: Platform,
    protected crop: Crop,
    protected alert: AlertService
  ) { }

  async pickImage(source: CameraSource, width = 0, height = 0, isCrop = true) {
    const cameraOptions: ImageOptions = {
      source,
      allowEditing: false,
      resultType: CameraResultType.Uri,
      correctOrientation: true,
      quality: 100
    };
    try {
      const imageData = await Camera.getPhoto(cameraOptions);

      if (!isCrop) {
        return this.resolveURL(imageData.webPath);
      }

      let path = imageData.path;
      if (this.platform.is('hybrid')) {
        path = await this.crop.crop(path, {
          quality: 100,
          targetHeight: height,
          targetWidth: width,
        });
        const base64Data = await Filesystem.readFile({ path });
        path = `data:image/jpeg;base64,${base64Data.data}`;
      } else {
        path = imageData.webPath;
      }

      return this.resolveURL(path);
    } catch (err) {
      return false;
    }
  }

  selectImage(width = 0, height = 0, isCrop = true) {
    return new Promise(async (resolve, reject) => {
      const actionSheet = await this.actionSheetController.create({
        header: 'Select Image source',
        buttons: [{
          text: 'Load from Library',
          icon: 'image',
          handler: () => {
            this.takePermission('photos').then((res) => {
              if (res) {
                this.pickImage(CameraSource.Photos, width, height, isCrop).then((val) => {
                  resolve(val);
                }).catch(() => reject(false));
              }
            });
          }
        },
        {
          text: 'Use Camera',
          icon: 'camera',
          handler: () => {
            this.takePermission('camera').then((res) => {
              if (res) {
                this.pickImage(CameraSource.Camera, width, height, isCrop).then((val) => {
                  resolve(val);
                }).catch(() => reject(false));
              }
            });
          }
        }
        ]
      });
      await actionSheet.present();
    });
  }

  selectMultipleImage(width = 0, height = 0, isCrop = true) {
    return new Promise(async (resolve, reject) => {
      const actionSheet = await this.actionSheetController.create({
        header: 'Select Image source',
        buttons: [{
          text: 'Load from Library',
          icon: 'image',
          handler: () => {
            this.takePermission('photos').then((res) => {
              if (res) {
                this.getMultipleImages(width, height, isCrop)
                  .then((response) => resolve(response))
                  .catch(() => reject(false));
              }
            });
          }
        },
        {
          text: 'Use Camera',
          icon: 'camera',
          handler: () => {
            this.takePermission('camera').then((res) => {
              if (res) {
                this.pickImage(CameraSource.Camera, width, height, isCrop)
                  .then((val) => {
                    resolve([val]);
                  })
                  .catch(() => reject(false));
              }
            });
          }
        }
        ]
      });
      await actionSheet.present();
    });
  }

  async resolveURL(filePath: string): Promise<{
    imgString: string;
    itemImage: Blob;
  }> {
    try {
      const res = await fetch(filePath);
      const itemImageBlob = await res.blob();
      return {
        imgString: URL.createObjectURL(itemImageBlob),
        itemImage: itemImageBlob
      };
    } catch (err) {
      console.error(err);
    }
  }

  async getMultipleImages(width, height, isCrop): Promise<{ imgString: string; itemImage: Blob }[]> {
    const cameraOptions: GalleryImageOptions = {
      correctOrientation: true,
      // height,
      // width,
      quality: 100
    };
    try {
      const galleryImages = await (await Camera.pickImages(cameraOptions)).photos;

      return new Promise(async (resolve) => {
        const imageArray: Array<{ imgString: string; itemImage: Blob }> = [];

        for (const image of galleryImages) {
          let path = image.path;
          if (this.platform.is('hybrid')) {
            if (isCrop) {
              path = await this.crop.crop(path, {
                quality: 100,
                targetHeight: height,
                targetWidth: width
              });
            }
            const base64Data = await Filesystem.readFile({ path });
            path = `data:image/jpeg;base64,${base64Data.data}`;
          } else {
            path = image.webPath;
          }

          const imgObj = await this.resolveURL(path);
          imageArray.push(imgObj);
          if (imageArray.length === galleryImages.length) {
            resolve(imageArray);
          }
        }
      });
    } catch (err) {
      console.log('error:imagePicker', err);
    }
  }

  private async takePermission(imageSource: CameraPermissionType) {
    try {
      const permissionGranted = await Camera.checkPermissions();
      if (permissionGranted[imageSource] === 'denied' && this.platform.is('ios')) {
        this.alert.showToaster('please allow camera/gallery permission from settings');
        return false;
      }
      if (permissionGranted[imageSource] === 'granted' || permissionGranted[imageSource] === 'limited') {
        return true;
      } else {
        const cameraPermission = await Camera.requestPermissions();
        return (cameraPermission[imageSource] === 'granted' || permissionGranted[imageSource] === 'limited');
      }
    } catch (e) {
      console.error(e);
    }
  }

}
