import ComponentLibrary
import Localization
import SwiftUI
import UIKit

public struct CameraView: UIViewControllerRepresentable {
    let showsCameraControls: Bool
    @Binding var didTapCapture: Bool
    @Binding var didTapFlipCamera: Bool
    let completion: (Result<UIImage, Error>) -> Void
    let cancel: () -> Void

    enum CameraViewError: LocalizedError {
        case unableToLoadImage

        var errorDescription: String? {
            switch self {
            case .unableToLoadImage: L10n.FeaturePhotoPicker.imageLoadingFailed
            }
        }
    }

    public init(
        showsCameraControls: Bool = true,
        didTapCapture: Binding<Bool> = .constant(false),
        didTapFlipCamera: Binding<Bool> = .constant(false),
        completion: @escaping (Result<UIImage, Error>) -> Void,
        cancel: @escaping () -> Void
    ) {
        self.completion = completion
        self._didTapCapture = didTapCapture
        self._didTapFlipCamera = didTapFlipCamera
        self.cancel = cancel
        self.showsCameraControls = showsCameraControls
    }

    public func makeUIViewController(context: Context) -> UIImagePickerController {
        let controller = UIImagePickerController()
        controller.sourceType = .camera
        controller.delegate = context.coordinator
        controller.showsCameraControls = showsCameraControls
        controller.cameraDevice = .rear
        return controller
    }

    public func updateUIViewController(_ uiViewController: UIImagePickerController, context _: Context) {
        DispatchQueue.main.async {
            if didTapCapture {
                uiViewController.takePicture()
                didTapCapture = false
            }

            if didTapFlipCamera {
                let isFront = uiViewController.cameraDevice == .front
                uiViewController.cameraDevice = isFront ? .rear : .front
                didTapFlipCamera = false
            }
        }
    }

    public func makeCoordinator() -> Coordinator {
        Coordinator(completion: completion, cancel: cancel)
    }

    public class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        let completion: (Result<UIImage, Error>) -> Void
        let cancel: () -> Void

        init(
            completion: @escaping (Result<UIImage, Error>) -> Void,
            cancel: @escaping () -> Void
        ) {
            self.completion = completion
            self.cancel = cancel
        }

        public func imagePickerController(_: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
            DispatchQueue.main.async { [weak self] in
                if let image = (info[.editedImage] ?? info[.originalImage]) as? UIImage {
                    self?.completion(.success(image.fixOrientation()))
                } else {
                    self?.completion(.failure(CameraViewError.unableToLoadImage))
                }
            }
        }

        public func imagePickerControllerDidCancel(_: UIImagePickerController) {
            DispatchQueue.main.async { [weak self] in
                self?.cancel()
            }
        }
    }
}
