// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:quiver/core.dart';

/// The state of a [CameraController].
class CameraValue {
  /// Creates a new camera controller state.
  const CameraValue({
    required this.isInitialized,
    this.previewSize,
    required this.isRecordingVideo,
    required this.isTakingPicture,
    required this.isStreamingImages,
    required this.isRecordingPaused,
    required this.flashMode,
    required this.exposureMode,
    required this.focusMode,
    required this.deviceOrientation,
    this.lockedCaptureOrientation,
    this.recordingOrientation,
    this.isPreviewPaused = false,
    this.previewPauseOrientation,
  });

  /// Creates a new camera controller state for an uninitialized controller.
  const CameraValue.uninitialized()
      : this(
          isInitialized: false,
          isRecordingVideo: false,
          isTakingPicture: false,
          isStreamingImages: false,
          isRecordingPaused: false,
          flashMode: FlashMode.auto,
          exposureMode: ExposureMode.auto,
          focusMode: FocusMode.auto,
          deviceOrientation: DeviceOrientation.portraitUp,
          isPreviewPaused: false,
        );

  /// True after [CameraController.initialize] has completed successfully.
  final bool isInitialized;

  /// True when a picture capture request has been sent but as not yet returned.
  final bool isTakingPicture;

  /// True when the camera is recording (not the same as previewing).
  final bool isRecordingVideo;

  /// True when images from the camera are being streamed.
  final bool isStreamingImages;

  /// True when video recording is paused.
  final bool isRecordingPaused;

  /// True when the preview widget has been paused manually.
  final bool isPreviewPaused;

  /// Set to the orientation the preview was paused in, if it is currently paused.
  final DeviceOrientation? previewPauseOrientation;

  /// The size of the preview in pixels.
  ///
  /// Is `null` until [isInitialized] is `true`.
  final Size? previewSize;

  /// The flash mode the camera is currently set to.
  final FlashMode flashMode;

  /// The exposure mode the camera is currently set to.
  final ExposureMode exposureMode;

  /// The focus mode the camera is currently set to.
  final FocusMode focusMode;

  /// The current device UI orientation.
  final DeviceOrientation deviceOrientation;

  /// The currently locked capture orientation.
  final DeviceOrientation? lockedCaptureOrientation;

  /// Whether the capture orientation is currently locked.
  bool get isCaptureOrientationLocked => lockedCaptureOrientation != null;

  /// The orientation of the currently running video recording.
  final DeviceOrientation? recordingOrientation;

  /// Creates a modified copy of the object.
  ///
  /// Explicitly specified fields get the specified value, all other fields get
  /// the same value of the current object.
  CameraValue copyWith({
    bool? isInitialized,
    bool? isRecordingVideo,
    bool? isTakingPicture,
    bool? isStreamingImages,
    Size? previewSize,
    bool? isRecordingPaused,
    FlashMode? flashMode,
    ExposureMode? exposureMode,
    FocusMode? focusMode,
    bool? exposurePointSupported,
    bool? focusPointSupported,
    DeviceOrientation? deviceOrientation,
    Optional<DeviceOrientation>? lockedCaptureOrientation,
    Optional<DeviceOrientation>? recordingOrientation,
    bool? isPreviewPaused,
    Optional<DeviceOrientation>? previewPauseOrientation,
  }) {
    return CameraValue(
      isInitialized: isInitialized ?? this.isInitialized,
      previewSize: previewSize ?? this.previewSize,
      isRecordingVideo: isRecordingVideo ?? this.isRecordingVideo,
      isTakingPicture: isTakingPicture ?? this.isTakingPicture,
      isStreamingImages: isStreamingImages ?? this.isStreamingImages,
      isRecordingPaused: isRecordingPaused ?? this.isRecordingPaused,
      flashMode: flashMode ?? this.flashMode,
      exposureMode: exposureMode ?? this.exposureMode,
      focusMode: focusMode ?? this.focusMode,
      deviceOrientation: deviceOrientation ?? this.deviceOrientation,
      lockedCaptureOrientation: lockedCaptureOrientation == null
          ? this.lockedCaptureOrientation
          : lockedCaptureOrientation.orNull,
      recordingOrientation: recordingOrientation == null
          ? this.recordingOrientation
          : recordingOrientation.orNull,
      isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused,
      previewPauseOrientation: previewPauseOrientation == null
          ? this.previewPauseOrientation
          : previewPauseOrientation.orNull,
    );
  }

  @override
  String toString() {
    return '${objectRuntimeType(this, 'CameraValue')}('
        'isRecordingVideo: $isRecordingVideo, '
        'isInitialized: $isInitialized, '
        'previewSize: $previewSize, '
        'isStreamingImages: $isStreamingImages, '
        'flashMode: $flashMode, '
        'exposureMode: $exposureMode, '
        'focusMode: $focusMode, '
        'deviceOrientation: $deviceOrientation, '
        'lockedCaptureOrientation: $lockedCaptureOrientation, '
        'recordingOrientation: $recordingOrientation, '
        'isPreviewPaused: $isPreviewPaused, '
        'previewPausedOrientation: $previewPauseOrientation)';
  }
}

/// Controls a device camera.
///
/// This is a stripped-down version of the app-facing controller to serve as a
/// utility for the example and integration tests. It wraps only the calls that
/// have state associated with them, to consolidate tracking of camera state
/// outside of the overall example code.
class CameraController extends ValueNotifier<CameraValue> {
  /// Creates a new camera controller in an uninitialized state.
  CameraController(
    this.description,
    this.resolutionPreset, {
    this.enableAudio = true,
    this.imageFormatGroup,
  }) : super(const CameraValue.uninitialized());

  /// The properties of the camera device controlled by this controller.
  final CameraDescription description;

  /// The resolution this controller is targeting.
  ///
  /// This resolution preset is not guaranteed to be available on the device,
  /// if unavailable a lower resolution will be used.
  ///
  /// See also: [ResolutionPreset].
  final ResolutionPreset resolutionPreset;

  /// Whether to include audio when recording a video.
  final bool enableAudio;

  /// The [ImageFormatGroup] describes the output of the raw image format.
  ///
  /// When null the imageFormat will fallback to the platforms default.
  final ImageFormatGroup? imageFormatGroup;

  late int _cameraId;

  bool _isDisposed = false;
  StreamSubscription<CameraImageData>? _imageStreamSubscription;
  FutureOr<bool>? _initCalled;
  StreamSubscription<DeviceOrientationChangedEvent>?
      _deviceOrientationSubscription;

  /// The camera identifier with which the controller is associated.
  int get cameraId => _cameraId;

  /// Initializes the camera on the device.
  Future<void> initialize() async {
    final Completer<CameraInitializedEvent> initializeCompleter =
        Completer<CameraInitializedEvent>();

    _deviceOrientationSubscription = CameraPlatform.instance
        .onDeviceOrientationChanged()
        .listen((DeviceOrientationChangedEvent event) {
      value = value.copyWith(
        deviceOrientation: event.orientation,
      );
    });

    _cameraId = await CameraPlatform.instance.createCamera(
      description,
      resolutionPreset,
      enableAudio: enableAudio,
    );

    CameraPlatform.instance
        .onCameraInitialized(_cameraId)
        .first
        .then((CameraInitializedEvent event) {
      initializeCompleter.complete(event);
    });

    await CameraPlatform.instance.initializeCamera(
      _cameraId,
      imageFormatGroup: imageFormatGroup ?? ImageFormatGroup.unknown,
    );

    value = value.copyWith(
      isInitialized: true,
      previewSize: await initializeCompleter.future
          .then((CameraInitializedEvent event) => Size(
                event.previewWidth,
                event.previewHeight,
              )),
      exposureMode: await initializeCompleter.future
          .then((CameraInitializedEvent event) => event.exposureMode),
      focusMode: await initializeCompleter.future
          .then((CameraInitializedEvent event) => event.focusMode),
      exposurePointSupported: await initializeCompleter.future
          .then((CameraInitializedEvent event) => event.exposurePointSupported),
      focusPointSupported: await initializeCompleter.future
          .then((CameraInitializedEvent event) => event.focusPointSupported),
    );

    _initCalled = true;
  }

  /// Prepare the capture session for video recording.
  Future<void> prepareForVideoRecording() async {
    await CameraPlatform.instance.prepareForVideoRecording();
  }

  /// Pauses the current camera preview
  Future<void> pausePreview() async {
    await CameraPlatform.instance.pausePreview(_cameraId);
    value = value.copyWith(
        isPreviewPaused: true,
        previewPauseOrientation: Optional<DeviceOrientation>.of(
            value.lockedCaptureOrientation ?? value.deviceOrientation));
  }

  /// Resumes the current camera preview
  Future<void> resumePreview() async {
    await CameraPlatform.instance.resumePreview(_cameraId);
    value = value.copyWith(
        isPreviewPaused: false,
        previewPauseOrientation: const Optional<DeviceOrientation>.absent());
  }

  /// Captures an image and returns the file where it was saved.
  ///
  /// Throws a [CameraException] if the capture fails.
  Future<XFile> takePicture() async {
    value = value.copyWith(isTakingPicture: true);
    final XFile file = await CameraPlatform.instance.takePicture(_cameraId);
    value = value.copyWith(isTakingPicture: false);
    return file;
  }

  /// Start streaming images from platform camera.
  Future<void> startImageStream(
      Function(CameraImageData image) onAvailable) async {
    _imageStreamSubscription = CameraPlatform.instance
        .onStreamedFrameAvailable(_cameraId)
        .listen((CameraImageData imageData) {
      onAvailable(imageData);
    });
    value = value.copyWith(isStreamingImages: true);
  }

  /// Stop streaming images from platform camera.
  Future<void> stopImageStream() async {
    value = value.copyWith(isStreamingImages: false);
    await _imageStreamSubscription?.cancel();
    _imageStreamSubscription = null;
  }

  /// Start a video recording.
  ///
  /// The video is returned as a [XFile] after calling [stopVideoRecording].
  /// Throws a [CameraException] if the capture fails.
  Future<void> startVideoRecording() async {
    await CameraPlatform.instance.startVideoRecording(_cameraId);
    value = value.copyWith(
        isRecordingVideo: true,
        isRecordingPaused: false,
        recordingOrientation: Optional<DeviceOrientation>.of(
            value.lockedCaptureOrientation ?? value.deviceOrientation));
  }

  /// Stops the video recording and returns the file where it was saved.
  ///
  /// Throws a [CameraException] if the capture failed.
  Future<XFile> stopVideoRecording() async {
    final XFile file =
        await CameraPlatform.instance.stopVideoRecording(_cameraId);
    value = value.copyWith(
      isRecordingVideo: false,
      recordingOrientation: const Optional<DeviceOrientation>.absent(),
    );
    return file;
  }

  /// Pause video recording.
  ///
  /// This feature is only available on iOS and Android sdk 24+.
  Future<void> pauseVideoRecording() async {
    await CameraPlatform.instance.pauseVideoRecording(_cameraId);
    value = value.copyWith(isRecordingPaused: true);
  }

  /// Resume video recording after pausing.
  ///
  /// This feature is only available on iOS and Android sdk 24+.
  Future<void> resumeVideoRecording() async {
    await CameraPlatform.instance.resumeVideoRecording(_cameraId);
    value = value.copyWith(isRecordingPaused: false);
  }

  /// Returns a widget showing a live camera preview.
  Widget buildPreview() {
    return CameraPlatform.instance.buildPreview(_cameraId);
  }

  /// Sets the flash mode for taking pictures.
  Future<void> setFlashMode(FlashMode mode) async {
    await CameraPlatform.instance.setFlashMode(_cameraId, mode);
    value = value.copyWith(flashMode: mode);
  }

  /// Sets the exposure mode for taking pictures.
  Future<void> setExposureMode(ExposureMode mode) async {
    await CameraPlatform.instance.setExposureMode(_cameraId, mode);
    value = value.copyWith(exposureMode: mode);
  }

  /// Sets the exposure offset for the selected camera.
  Future<double> setExposureOffset(double offset) async {
    // Check if offset is in range
    final List<double> range = await Future.wait(<Future<double>>[
      CameraPlatform.instance.getMinExposureOffset(_cameraId),
      CameraPlatform.instance.getMaxExposureOffset(_cameraId)
    ]);

    // Round to the closest step if needed
    final double stepSize =
        await CameraPlatform.instance.getExposureOffsetStepSize(_cameraId);
    if (stepSize > 0) {
      final double inv = 1.0 / stepSize;
      double roundedOffset = (offset * inv).roundToDouble() / inv;
      if (roundedOffset > range[1]) {
        roundedOffset = (offset * inv).floorToDouble() / inv;
      } else if (roundedOffset < range[0]) {
        roundedOffset = (offset * inv).ceilToDouble() / inv;
      }
      offset = roundedOffset;
    }

    return CameraPlatform.instance.setExposureOffset(_cameraId, offset);
  }

  /// Locks the capture orientation.
  ///
  /// If [orientation] is omitted, the current device orientation is used.
  Future<void> lockCaptureOrientation() async {
    await CameraPlatform.instance
        .lockCaptureOrientation(_cameraId, value.deviceOrientation);
    value = value.copyWith(
        lockedCaptureOrientation:
            Optional<DeviceOrientation>.of(value.deviceOrientation));
  }

  /// Unlocks the capture orientation.
  Future<void> unlockCaptureOrientation() async {
    await CameraPlatform.instance.unlockCaptureOrientation(_cameraId);
    value = value.copyWith(
        lockedCaptureOrientation: const Optional<DeviceOrientation>.absent());
  }

  /// Sets the focus mode for taking pictures.
  Future<void> setFocusMode(FocusMode mode) async {
    await CameraPlatform.instance.setFocusMode(_cameraId, mode);
    value = value.copyWith(focusMode: mode);
  }

  /// Releases the resources of this camera.
  @override
  Future<void> dispose() async {
    if (_isDisposed) {
      return;
    }
    _deviceOrientationSubscription?.cancel();
    _isDisposed = true;
    super.dispose();
    if (_initCalled != null) {
      await _initCalled;
      await CameraPlatform.instance.dispose(_cameraId);
    }
  }

  @override
  void removeListener(VoidCallback listener) {
    // Prevent ValueListenableBuilder in CameraPreview widget from causing an
    // exception to be thrown by attempting to remove its own listener after
    // the controller has already been disposed.
    if (!_isDisposed) {
      super.removeListener(listener);
    }
  }
}
