// 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 'dart:html' as html;
import 'dart:math';

import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:camera_web/src/camera.dart';
import 'package:camera_web/src/camera_service.dart';
import 'package:camera_web/src/types/types.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:stream_transform/stream_transform.dart';

// The default error message, when the error is an empty string.
// See: https://developer.mozilla.org/en-US/docs/Web/API/MediaError/message
const String _kDefaultErrorMessage =
    'No further diagnostic information can be determined or provided.';

/// The web implementation of [CameraPlatform].
///
/// This class implements the `package:camera` functionality for the web.
class CameraPlugin extends CameraPlatform {
  /// Creates a new instance of [CameraPlugin]
  /// with the given [cameraService].
  CameraPlugin({required CameraService cameraService})
      : _cameraService = cameraService;

  /// Registers this class as the default instance of [CameraPlatform].
  static void registerWith(Registrar registrar) {
    CameraPlatform.instance = CameraPlugin(
      cameraService: CameraService(),
    );
  }

  final CameraService _cameraService;

  /// The cameras managed by the [CameraPlugin].
  @visibleForTesting
  final cameras = <int, Camera>{};
  var _textureCounter = 1;

  /// Metadata associated with each camera description.
  /// Populated in [availableCameras].
  @visibleForTesting
  final camerasMetadata = <CameraDescription, CameraMetadata>{};

  /// The controller used to broadcast different camera events.
  ///
  /// It is `broadcast` as multiple controllers may subscribe
  /// to different stream views of this controller.
  @visibleForTesting
  final cameraEventStreamController = StreamController<CameraEvent>.broadcast();

  final _cameraVideoErrorSubscriptions =
      <int, StreamSubscription<html.Event>>{};

  final _cameraVideoAbortSubscriptions =
      <int, StreamSubscription<html.Event>>{};

  final _cameraEndedSubscriptions =
      <int, StreamSubscription<html.MediaStreamTrack>>{};

  final _cameraVideoRecordingErrorSubscriptions =
      <int, StreamSubscription<html.ErrorEvent>>{};

  /// Returns a stream of camera events for the given [cameraId].
  Stream<CameraEvent> _cameraEvents(int cameraId) =>
      cameraEventStreamController.stream
          .where((event) => event.cameraId == cameraId);

  /// The current browser window used to access media devices.
  @visibleForTesting
  html.Window? window = html.window;

  @override
  Future<List<CameraDescription>> availableCameras() async {
    try {
      final mediaDevices = window?.navigator.mediaDevices;
      final cameras = <CameraDescription>[];

      // Throw a not supported exception if the current browser window
      // does not support any media devices.
      if (mediaDevices == null) {
        throw PlatformException(
          code: CameraErrorCode.notSupported.toString(),
          message: 'The camera is not supported on this device.',
        );
      }

      // Request video and audio permissions.
      final cameraStream = await _cameraService.getMediaStreamForOptions(
        CameraOptions(
          audio: AudioConstraints(enabled: true),
        ),
      );

      // Release the camera stream used to request video and audio permissions.
      cameraStream.getVideoTracks().forEach((videoTrack) => videoTrack.stop());

      // Request available media devices.
      final devices = await mediaDevices.enumerateDevices();

      // Filter video input devices.
      final videoInputDevices = devices
          .whereType<html.MediaDeviceInfo>()
          .where((device) => device.kind == MediaDeviceKind.videoInput)

          /// The device id property is currently not supported on Internet Explorer:
          /// https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo/deviceId#browser_compatibility
          .where(
            (device) => device.deviceId != null && device.deviceId!.isNotEmpty,
          );

      // Map video input devices to camera descriptions.
      for (final videoInputDevice in videoInputDevices) {
        // Get the video stream for the current video input device
        // to later use for the available video tracks.
        final videoStream = await _getVideoStreamForDevice(
          videoInputDevice.deviceId!,
        );

        // Get all video tracks in the video stream
        // to later extract the lens direction from the first track.
        final videoTracks = videoStream.getVideoTracks();

        if (videoTracks.isNotEmpty) {
          // Get the facing mode from the first available video track.
          final facingMode =
              _cameraService.getFacingModeForVideoTrack(videoTracks.first);

          // Get the lens direction based on the facing mode.
          // Fallback to the external lens direction
          // if the facing mode is not available.
          final lensDirection = facingMode != null
              ? _cameraService.mapFacingModeToLensDirection(facingMode)
              : CameraLensDirection.external;

          // Create a camera description.
          //
          // The name is a camera label which might be empty
          // if no permissions to media devices have been granted.
          //
          // MediaDeviceInfo.label:
          // https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo/label
          //
          // Sensor orientation is currently not supported.
          final cameraLabel = videoInputDevice.label ?? '';
          final camera = CameraDescription(
            name: cameraLabel,
            lensDirection: lensDirection,
            sensorOrientation: 0,
          );

          final cameraMetadata = CameraMetadata(
            deviceId: videoInputDevice.deviceId!,
            facingMode: facingMode,
          );

          cameras.add(camera);

          camerasMetadata[camera] = cameraMetadata;

          // Release the camera stream of the current video input device.
          videoTracks.forEach((videoTrack) => videoTrack.stop());
        } else {
          // Ignore as no video tracks exist in the current video input device.
          continue;
        }
      }

      return cameras;
    } on html.DomException catch (e) {
      throw CameraException(e.name, e.message);
    } on PlatformException catch (e) {
      throw CameraException(e.code, e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw CameraException(e.code.toString(), e.description);
    }
  }

  @override
  Future<int> createCamera(
    CameraDescription cameraDescription,
    ResolutionPreset? resolutionPreset, {
    bool enableAudio = false,
  }) async {
    try {
      if (!camerasMetadata.containsKey(cameraDescription)) {
        throw PlatformException(
          code: CameraErrorCode.missingMetadata.toString(),
          message:
              'Missing camera metadata. Make sure to call `availableCameras` before creating a camera.',
        );
      }

      final textureId = _textureCounter++;

      final cameraMetadata = camerasMetadata[cameraDescription]!;

      final cameraType = cameraMetadata.facingMode != null
          ? _cameraService.mapFacingModeToCameraType(cameraMetadata.facingMode!)
          : null;

      // Use the highest resolution possible
      // if the resolution preset is not specified.
      final videoSize = _cameraService
          .mapResolutionPresetToSize(resolutionPreset ?? ResolutionPreset.max);

      // Create a camera with the given audio and video constraints.
      // Sensor orientation is currently not supported.
      final camera = Camera(
        textureId: textureId,
        cameraService: _cameraService,
        options: CameraOptions(
          audio: AudioConstraints(enabled: enableAudio),
          video: VideoConstraints(
            facingMode:
                cameraType != null ? FacingModeConstraint(cameraType) : null,
            width: VideoSizeConstraint(
              ideal: videoSize.width.toInt(),
            ),
            height: VideoSizeConstraint(
              ideal: videoSize.height.toInt(),
            ),
            deviceId: cameraMetadata.deviceId,
          ),
        ),
      );

      cameras[textureId] = camera;

      return textureId;
    } on PlatformException catch (e) {
      throw CameraException(e.code, e.message);
    }
  }

  @override
  Future<void> initializeCamera(
    int cameraId, {
    // The image format group is currently not supported.
    ImageFormatGroup imageFormatGroup = ImageFormatGroup.unknown,
  }) async {
    try {
      final camera = getCamera(cameraId);

      await camera.initialize();

      // Add camera's video error events to the camera events stream.
      // The error event fires when the video element's source has failed to load, or can't be used.
      _cameraVideoErrorSubscriptions[cameraId] =
          camera.videoElement.onError.listen((html.Event _) {
        // The Event itself (_) doesn't contain information about the actual error.
        // We need to look at the HTMLMediaElement.error.
        // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/error
        final error = camera.videoElement.error!;
        final errorCode = CameraErrorCode.fromMediaError(error);
        final errorMessage =
            error.message != '' ? error.message : _kDefaultErrorMessage;

        cameraEventStreamController.add(
          CameraErrorEvent(
            cameraId,
            'Error code: ${errorCode}, error message: ${errorMessage}',
          ),
        );
      });

      // Add camera's video abort events to the camera events stream.
      // The abort event fires when the video element's source has not fully loaded.
      _cameraVideoAbortSubscriptions[cameraId] =
          camera.videoElement.onAbort.listen((html.Event _) {
        cameraEventStreamController.add(
          CameraErrorEvent(
            cameraId,
            'Error code: ${CameraErrorCode.abort}, error message: The video element\'s source has not fully loaded.',
          ),
        );
      });

      await camera.play();

      // Add camera's closing events to the camera events stream.
      // The onEnded stream fires when there is no more camera stream data.
      _cameraEndedSubscriptions[cameraId] =
          camera.onEnded.listen((html.MediaStreamTrack _) {
        cameraEventStreamController.add(
          CameraClosingEvent(cameraId),
        );
      });

      final cameraSize = camera.getVideoSize();

      cameraEventStreamController.add(
        CameraInitializedEvent(
          cameraId,
          cameraSize.width,
          cameraSize.height,
          // TODO(camera_web): Add support for exposure mode and point (https://github.com/flutter/flutter/issues/86857).
          ExposureMode.auto,
          false,
          // TODO(camera_web): Add support for focus mode and point (https://github.com/flutter/flutter/issues/86858).
          FocusMode.auto,
          false,
        ),
      );
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Stream<CameraInitializedEvent> onCameraInitialized(int cameraId) {
    return _cameraEvents(cameraId).whereType<CameraInitializedEvent>();
  }

  /// Emits an empty stream as there is no event corresponding to a change
  /// in the camera resolution on the web.
  ///
  /// In order to change the camera resolution a new camera with appropriate
  /// [CameraOptions.video] constraints has to be created and initialized.
  @override
  Stream<CameraResolutionChangedEvent> onCameraResolutionChanged(int cameraId) {
    return const Stream.empty();
  }

  @override
  Stream<CameraClosingEvent> onCameraClosing(int cameraId) {
    return _cameraEvents(cameraId).whereType<CameraClosingEvent>();
  }

  @override
  Stream<CameraErrorEvent> onCameraError(int cameraId) {
    return _cameraEvents(cameraId).whereType<CameraErrorEvent>();
  }

  @override
  Stream<VideoRecordedEvent> onVideoRecordedEvent(int cameraId) {
    return getCamera(cameraId).onVideoRecordedEvent;
  }

  @override
  Stream<DeviceOrientationChangedEvent> onDeviceOrientationChanged() {
    final orientation = window?.screen?.orientation;

    if (orientation != null) {
      // Create an initial orientation event that emits the device orientation
      // as soon as subscribed to this stream.
      final initialOrientationEvent = html.Event("change");

      return orientation.onChange.startWith(initialOrientationEvent).map(
        (html.Event _) {
          final deviceOrientation = _cameraService
              .mapOrientationTypeToDeviceOrientation(orientation.type!);
          return DeviceOrientationChangedEvent(deviceOrientation);
        },
      );
    } else {
      return const Stream.empty();
    }
  }

  @override
  Future<void> lockCaptureOrientation(
    int cameraId,
    DeviceOrientation deviceOrientation,
  ) async {
    try {
      final orientation = window?.screen?.orientation;
      final documentElement = window?.document.documentElement;

      if (orientation != null && documentElement != null) {
        final orientationType = _cameraService
            .mapDeviceOrientationToOrientationType(deviceOrientation);

        // Full-screen mode may be required to modify the device orientation.
        // See: https://w3c.github.io/screen-orientation/#interaction-with-fullscreen-api
        // Recent versions of Dart changed requestFullscreen to return a Future instead of void.
        // This wrapper allows use of both the old and new APIs.
        dynamic fullScreen() => documentElement.requestFullscreen();
        await fullScreen();
        await orientation.lock(orientationType.toString());
      } else {
        throw PlatformException(
          code: CameraErrorCode.orientationNotSupported.toString(),
          message: 'Orientation is not supported in the current browser.',
        );
      }
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    }
  }

  @override
  Future<void> unlockCaptureOrientation(int cameraId) async {
    try {
      final orientation = window?.screen?.orientation;
      final documentElement = window?.document.documentElement;

      if (orientation != null && documentElement != null) {
        orientation.unlock();
      } else {
        throw PlatformException(
          code: CameraErrorCode.orientationNotSupported.toString(),
          message: 'Orientation is not supported in the current browser.',
        );
      }
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    }
  }

  @override
  Future<XFile> takePicture(int cameraId) {
    try {
      return getCamera(cameraId).takePicture();
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Future<void> prepareForVideoRecording() async {
    // This is a no-op as it is not required for the web.
  }

  @override
  Future<void> startVideoRecording(int cameraId, {Duration? maxVideoDuration}) {
    try {
      final camera = getCamera(cameraId);

      // Add camera's video recording errors to the camera events stream.
      // The error event fires when the video recording is not allowed or an unsupported
      // codec is used.
      _cameraVideoRecordingErrorSubscriptions[cameraId] =
          camera.onVideoRecordingError.listen((html.ErrorEvent errorEvent) {
        cameraEventStreamController.add(
          CameraErrorEvent(
            cameraId,
            'Error code: ${errorEvent.type}, error message: ${errorEvent.message}.',
          ),
        );
      });

      return camera.startVideoRecording(maxVideoDuration: maxVideoDuration);
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Future<XFile> stopVideoRecording(int cameraId) async {
    try {
      final videoRecording = await getCamera(cameraId).stopVideoRecording();
      await _cameraVideoRecordingErrorSubscriptions[cameraId]?.cancel();
      return videoRecording;
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Future<void> pauseVideoRecording(int cameraId) {
    try {
      return getCamera(cameraId).pauseVideoRecording();
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Future<void> resumeVideoRecording(int cameraId) {
    try {
      return getCamera(cameraId).resumeVideoRecording();
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Future<void> setFlashMode(int cameraId, FlashMode mode) async {
    try {
      getCamera(cameraId).setFlashMode(mode);
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Future<void> setExposureMode(int cameraId, ExposureMode mode) {
    throw UnimplementedError('setExposureMode() is not implemented.');
  }

  @override
  Future<void> setExposurePoint(int cameraId, Point<double>? point) {
    throw UnimplementedError('setExposurePoint() is not implemented.');
  }

  @override
  Future<double> getMinExposureOffset(int cameraId) {
    throw UnimplementedError('getMinExposureOffset() is not implemented.');
  }

  @override
  Future<double> getMaxExposureOffset(int cameraId) {
    throw UnimplementedError('getMaxExposureOffset() is not implemented.');
  }

  @override
  Future<double> getExposureOffsetStepSize(int cameraId) {
    throw UnimplementedError('getExposureOffsetStepSize() is not implemented.');
  }

  @override
  Future<double> setExposureOffset(int cameraId, double offset) {
    throw UnimplementedError('setExposureOffset() is not implemented.');
  }

  @override
  Future<void> setFocusMode(int cameraId, FocusMode mode) {
    throw UnimplementedError('setFocusMode() is not implemented.');
  }

  @override
  Future<void> setFocusPoint(int cameraId, Point<double>? point) {
    throw UnimplementedError('setFocusPoint() is not implemented.');
  }

  @override
  Future<double> getMaxZoomLevel(int cameraId) async {
    try {
      return getCamera(cameraId).getMaxZoomLevel();
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Future<double> getMinZoomLevel(int cameraId) async {
    try {
      return getCamera(cameraId).getMinZoomLevel();
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Future<void> setZoomLevel(int cameraId, double zoom) async {
    try {
      getCamera(cameraId).setZoomLevel(zoom);
    } on html.DomException catch (e) {
      throw CameraException(e.name, e.message);
    } on PlatformException catch (e) {
      throw CameraException(e.code, e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw CameraException(e.code.toString(), e.description);
    }
  }

  @override
  Future<void> pausePreview(int cameraId) async {
    try {
      getCamera(cameraId).pause();
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    }
  }

  @override
  Future<void> resumePreview(int cameraId) async {
    try {
      await getCamera(cameraId).play();
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    } on CameraWebException catch (e) {
      _addCameraErrorEvent(e);
      throw PlatformException(code: e.code.toString(), message: e.description);
    }
  }

  @override
  Widget buildPreview(int cameraId) {
    return HtmlElementView(
      viewType: getCamera(cameraId).getViewType(),
    );
  }

  @override
  Future<void> dispose(int cameraId) async {
    try {
      await getCamera(cameraId).dispose();
      await _cameraVideoErrorSubscriptions[cameraId]?.cancel();
      await _cameraVideoAbortSubscriptions[cameraId]?.cancel();
      await _cameraEndedSubscriptions[cameraId]?.cancel();
      await _cameraVideoRecordingErrorSubscriptions[cameraId]?.cancel();

      cameras.remove(cameraId);
      _cameraVideoErrorSubscriptions.remove(cameraId);
      _cameraVideoAbortSubscriptions.remove(cameraId);
      _cameraEndedSubscriptions.remove(cameraId);
    } on html.DomException catch (e) {
      throw PlatformException(code: e.name, message: e.message);
    }
  }

  /// Returns a media video stream for the device with the given [deviceId].
  Future<html.MediaStream> _getVideoStreamForDevice(
    String deviceId,
  ) {
    // Create camera options with the desired device id.
    final cameraOptions = CameraOptions(
      video: VideoConstraints(deviceId: deviceId),
    );

    return _cameraService.getMediaStreamForOptions(cameraOptions);
  }

  /// Returns a camera for the given [cameraId].
  ///
  /// Throws a [CameraException] if the camera does not exist.
  @visibleForTesting
  Camera getCamera(int cameraId) {
    final camera = cameras[cameraId];

    if (camera == null) {
      throw PlatformException(
        code: CameraErrorCode.notFound.toString(),
        message: 'No camera found for the given camera id $cameraId.',
      );
    }

    return camera;
  }

  /// Adds a [CameraErrorEvent], associated with the [exception],
  /// to the stream of camera events.
  void _addCameraErrorEvent(CameraWebException exception) {
    cameraEventStreamController.add(
      CameraErrorEvent(
        exception.cameraId,
        'Error code: ${exception.code}, error message: ${exception.description}',
      ),
    );
  }
}
