import Foundation
import UIKit
import ScanbotSDK
import ScanbotSDKNativeWrapper

@objc
public class RNScanbotCroppingViewController: UIViewController {
    
    private var editingViewController: SBSDKImageEditingViewController?
    private var isAttached: Bool = false
    private var sourceImage: SBSDKImageRef = SBSDKImageRef.fromUIImage(image: UIImage.placeholderImage())
    private var defaultValues = RNScanbotCroppingLegacyViewDefaultValues()
    @objc public var delegate: RNScanbotCroppingViewEventsDelegate?
    
    public override func viewDidLoad() {
        super.viewDidLoad()
        
        setImageSource()
    }

    // MARK: Sources
    
    @objc
    public func setImageFileSrc(_ value: NSString?, attached: Bool){
        
        guard let value = value as? String,
              !value.isEmpty,
              let ref = try? SBImage(imageFilePath: value as String).ref
        else {
            delegate?.onError(SBError(error: SBSDKError.invalidImageRef("Invalid image file path")))
            return
        }
        
        self.sourceImage = ref
        if attached { setImageSource() }
    }
    
    @objc
    public func setImageRefSrc(_ value: String?, attached: Bool){
        
        guard let value = value, !value.isEmpty ,let uuid = UUID(uuidString: value)
        else {
            delegate?.onError(SBError(error: SBSDKError.invalidImageRef("Invalid image ref uuid")))
            return
        }
        
        self.sourceImage = SBSDKImageRef(uniqueId: uuid, acquireStrongReference: true)
        if attached { setImageSource() }
    }
    
    // MARK: Polygon configuration
    
    @objc
    public func setEdgeColor(_ value: UIColor?){
        editingViewController?.edgeColor = value ?? defaultValues.edgeColor
    }
    
    @objc
    public func setEdgeLineWidth(_ value: NSNumber?){
        if (value != nil) {
            editingViewController?.edgeLineWidth = CGFloat(value!.floatValue)
        } else {
            editingViewController?.edgeLineWidth = defaultValues.edgeLineWidth
        }
    }
    
    @objc
    public func setEdgeColorOnLine(_ value: UIColor?){
        editingViewController?.magneticEdgeColor = value ?? defaultValues.edgeColorOnLine
    }
    
    @objc
    public func setAnchorPointsColor(_ value: UIColor?){
        editingViewController?.anchorPointsColor = value ?? defaultValues.anchorPointsColors
    }
    
    //MARK: Commands
    
    @objc
    public func resetPolygon(){
        editingViewController?.resetPolygon()
    }
    
    @objc
    public func detectPolygon(){
        do {
            try editingViewController?.detectPolygon()
        } catch {
            delegate?.onError(SBError(error: error))
        }
    }
    
    @objc
    public func rotate(_ value: Bool){
        do {
            try editingViewController?.rotateInputImageClockwise(value, animated: true)
        } catch {
            delegate?.onError(SBError(error: error))
        }
    }
    
    @objc
    public func extractCroppedArea(){
        guard let editingViewController = editingViewController
        else {
            return
        }
        
        let result = CroppingViewCroppedAreaResult(
            polygon: editingViewController.polygon.polygonPoints(),
            rotation: SBSDKImageRotation.enumValue(from: editingViewController.rotations) ?? SBSDKImageRotation.none,
            sourceImage: editingViewController.croppedImage!
        )
        
        guard let json = SBComponentUtils.encodeToString(value: result)
        else {
            delegate?.onError(SBError.resultError(reason: "Failed to encode cropping result"))
            return
        }
        
        delegate?.onExtractCroppingArea(json)
    }
    
    // MARK: Utils
    
    @objc public func attachController(parentViewController: UIViewController?, inView view: UIView){
        parentViewController?.sbsdk_attach(self, in: view)
    }
    
    @objc public func detachController(){
        self.sbsdk_detach(self)
    }
    
    private func createEditingViewController(image: SBSDKImageRef, currentController editingViewController: SBSDKImageEditingViewController?) -> SBSDKImageEditingViewController? {
        
        do {
            if let editingViewController = editingViewController {
                let newController = try SBSDKImageEditingViewController.create(image: image, polygon: nil)
                newController.edgeColor = editingViewController.edgeColor
                newController.edgeLineWidth = editingViewController.edgeLineWidth
                newController.magneticEdgeColor = editingViewController.magneticEdgeColor
                newController.anchorPointsColor = editingViewController.anchorPointsColor
                newController.contentInsets = editingViewController.contentInsets
                
                return newController
            } else {
                let newController = try SBSDKImageEditingViewController.create(image: image, polygon: nil)
                newController.edgeColor = defaultValues.edgeColor
                newController.edgeLineWidth = defaultValues.edgeLineWidth
                newController.magneticEdgeColor = defaultValues.edgeColorOnLine
                newController.anchorPointsColor = defaultValues.anchorPointsColors
                
                return newController
            }
        } catch {
            delegate?.onError(SBError(error: error))
            return nil
        }
    }
    
    private func setImageSource(){
        
        guard let viewController = createEditingViewController(image: sourceImage, currentController: self.editingViewController)
        else {
            return
        }
        
        if isAttached, let currentController = self.editingViewController {
            self.sbsdk_detach(currentController)
        }
        
        self.editingViewController = viewController;
                
        self.sbsdk_attach(viewController, in: self.view)
        isAttached = true
    }
    
}
