//
//  CircleCropViewController.swift
//  CIrcleCropView
//
//  Created by Bhavesh Chaudhari on 08/05/20.
//  Copyright © 2020 Bhavesh. All rights reserved.
//

import UIKit

public class CropViewController: UIViewController {
    var image: UIImage
    let imageView: UIImageView
    let scrollView: UIScrollView
    let completion: (UIImage?) -> Void
    private var circleView: CircleCropView?

    var backButton: StyleButton = {
        let button = StyleButton()
        button.tertiary(size: .large)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle("Cancel", for: .normal)
        return button
    }()

    var okButton: StyleButton = {
        let button = StyleButton()
        button.primary(size: .large)
        button.setTitle("Confirm", for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    public init(image: UIImage, completion: @escaping (UIImage?) -> Void) {
        self.image = image
        self.completion = completion
        imageView = UIImageView(image: image)
        scrollView = UIScrollView()
        scrollView.contentInsetAdjustmentBehavior = .never
        super.init(nibName: nil, bundle: nil)
    }

    override public func viewDidLoad() {
        super.viewDidLoad()
        circleView = CircleCropView(frame: view.bounds)
        view.addSubview(scrollView)
        view.addSubview(circleView!)
        view.addSubview(okButton)
        view.addSubview(backButton)
        scrollView.addSubview(imageView)
        scrollView.contentSize = image.size
        scrollView.delegate = self
        view.backgroundColor = UIColor(red: 33/255.0, green: 26/255.0, blue: 43/255.0, alpha: 1)
        scrollView.frame = view.frame//.inset(by: view.safeAreaInsets)
        circleView?.frame = scrollView.frame//.inset(by: view.safeAreaInsets)
       
        backButton.addTarget(self, action: #selector(backClick), for: .touchUpInside)
        okButton.addTarget(self, action: #selector(okClick), for: .touchUpInside)
        
        modalPresentationStyle = .fullScreen
        
        addConstraint()
    }

    func addConstraint() {
        backButton.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(24)
            make.bottom.equalToSuperview().offset(-16-UIWindow.safeAreaBottom*0.5)
        }
        okButton.snp.makeConstraints { make in
            make.trailing.equalToSuperview().offset(-24)
            make.bottom.equalToSuperview().offset(-16-UIWindow.safeAreaBottom*0.5)
        }
    }

    override public var preferredStatusBarStyle: UIStatusBarStyle {
        return .default
    }

    override public func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: animated)
    }

    override public func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        let scrollFrame = scrollView.frame
        let imSize = image.size
        guard let hole = circleView?.circleInset, hole.width > 0 else { return }
        let verticalRatio = hole.height / imSize.height
        let horizontalRatio = hole.width / imSize.width
        let maxRatio = max(horizontalRatio, verticalRatio)
        if(maxRatio > 1){ // 图比裁剪区域小
            scrollView.minimumZoomScale = maxRatio
            scrollView.maximumZoomScale = maxRatio * 2
            scrollView.zoomScale = maxRatio
        }else{
            scrollView.minimumZoomScale = maxRatio
            scrollView.maximumZoomScale = 1
            scrollView.zoomScale = scrollView.minimumZoomScale
        }
        
        
        let insetHeight = (scrollFrame.height - hole.height) / 2
        let insetWidth = (scrollFrame.width - hole.width) / 2
        scrollView.contentInset = UIEdgeInsets(top: insetHeight, left: insetWidth, bottom: insetHeight, right: insetWidth)
        okButton.clipsToBounds = true
    }

    override public func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.setNavigationBarHidden(false, animated: animated)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    @objc func backClick(sender: UIButton) {
        dismiss(animated: true, completion: nil)
    }

    @objc func okClick(sender: UIButton) {
        cropImage()
    }

    private func cropImage() {
        guard let rect = circleView?.circleInset else { return }
        let shift = rect.applying(CGAffineTransform(translationX: scrollView.contentOffset.x, y: scrollView.contentOffset.y))
        let scaled = shift.applying(CGAffineTransform(scaleX: 1.0 / scrollView.zoomScale, y: 1.0 / scrollView.zoomScale))
        let newImage = image.imageCropped(toRect: scaled)
        completion(newImage)
        dismiss(animated: true, completion: nil)
    }
}

extension CropViewController: UIScrollViewDelegate {
    func zoomOut() {
        let newScale = scrollView.zoomScale == scrollView.minimumZoomScale ? 0.5 : scrollView.minimumZoomScale
        scrollView.setZoomScale(newScale, animated: true)
    }

    public func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }

    public func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
        // need empty implementation for zooming
    }
}

extension UIImage {
    func imageCropped(toRect rect: CGRect) -> UIImage {
        let rad: (Double) -> CGFloat = { deg in
            CGFloat(deg / 180.0 * .pi)
        }
        var rectTransform: CGAffineTransform
        switch imageOrientation {
        case .left:
            let rotation = CGAffineTransform(rotationAngle: rad(90))
            rectTransform = rotation.translatedBy(x: 0, y: -size.height)
        case .right:
            let rotation = CGAffineTransform(rotationAngle: rad(-90))
            rectTransform = rotation.translatedBy(x: -size.width, y: 0)
        case .down:
            let rotation = CGAffineTransform(rotationAngle: rad(-180))
            rectTransform = rotation.translatedBy(x: -size.width, y: -size.height)
        default:
            rectTransform = .identity
        }
        rectTransform = rectTransform.scaledBy(x: scale, y: scale)
        let transformedRect = rect.applying(rectTransform)
        let imageRef = cgImage!.cropping(to: transformedRect)!
        let result = UIImage(cgImage: imageRef, scale: scale, orientation: imageOrientation)
        print("croped Image width and height = \(result.size)")
        return result
    }
}
