// 
// Copyright 2020 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation

@objc enum PiPAnimationType: Int {
    case enter
    case exit
}

@objcMembers
class PiPAnimator: NSObject {
    
    private enum Constants {
        static let pipViewSize: CGSize = CGSize(width: 90, height: 130)
    }

    let animationDuration: TimeInterval
    let animationType: PiPAnimationType
    weak var pipViewDelegate: PiPViewDelegate?
    
    init(animationDuration: TimeInterval,
         animationType: PiPAnimationType,
         pipViewDelegate: PiPViewDelegate?) {
        self.animationDuration = animationDuration
        self.animationType = animationType
        self.pipViewDelegate = pipViewDelegate
        super.init()
    }
    
    private func enterAnimation(context: UIViewControllerContextTransitioning) {
        guard let keyWindow = UIApplication.shared.keyWindow else {
            context.completeTransition(false)
            return
        }
        
        guard let fromVC = context.viewController(forKey: .from) else {
            context.completeTransition(false)
            return
        }
        
        if let pipable = fromVC as? PictureInPicturable {
            pipable.willEnterPiP?()
        }
        
        fromVC.willMove(toParent: nil)
        //  TODO: find a way to call this at the end of animation
        context.completeTransition(true)
        fromVC.removeFromParent()
        
        let pipView = PiPView(frame: fromVC.view.bounds)
        pipView.contentView = fromVC.view
        pipView.delegate = pipViewDelegate
        keyWindow.addSubview(pipView)
        
        let scale = Constants.pipViewSize.width/pipView.frame.width
        let transform = CGAffineTransform(scaleX: scale, y: scale)
        let targetSize = Constants.pipViewSize
        pipView.cornerRadius = pipView.cornerRadius / scale
        
        let animator = UIViewPropertyAnimator(duration: animationDuration, dampingRatio: 1) {
            pipView.transform = transform
            
            pipView.move(in: keyWindow,
                         targetSize: targetSize)
        }
        
        animator.addCompletion { (position) in
            if let pipable = fromVC as? PictureInPicturable {
                pipable.didEnterPiP?()
            }
            fromVC.dismiss(animated: false, completion: nil)
        }

        animator.startAnimation()
    }
    
    private func exitAnimation(context: UIViewControllerContextTransitioning) {
        guard let keyWindow = UIApplication.shared.keyWindow else {
            context.completeTransition(false)
            return
        }
        
        guard let toVC = context.viewController(forKey: .to) else {
            context.completeTransition(false)
            return
        }
        
        if let pipable = toVC as? PictureInPicturable {
            pipable.willExitPiP?()
        }
        
        guard let snapshot = toVC.view.snapshotView(afterScreenUpdates: true) else {
            context.completeTransition(false)
            return
        }
        
        guard let pipView = toVC.view.superview as? PiPView else {
            return
        }
        
        context.containerView.addSubview(toVC.view)
        context.containerView.addSubview(snapshot)
        toVC.view.isHidden = true
        
        toVC.additionalSafeAreaInsets = keyWindow.safeAreaInsets
        
        pipView.contentView = nil
        pipView.removeFromSuperview()
        
        snapshot.frame = pipView.frame
        
        let animator = UIViewPropertyAnimator(duration: animationDuration, dampingRatio: 1) {
            snapshot.frame = context.finalFrame(for: toVC)
        }
        
        animator.addCompletion { (position) in
            
            toVC.additionalSafeAreaInsets = .zero
            toVC.view.frame = context.finalFrame(for: toVC)
            toVC.view.isHidden = false
            
            snapshot.removeFromSuperview()
            if let pipable = toVC as? PictureInPicturable {
                pipable.didExitPiP?()
            }
            
            context.completeTransition(!context.transitionWasCancelled)
        }

        animator.startAnimation()
    }
}

extension PiPAnimator: UIViewControllerAnimatedTransitioning {
    
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return animationDuration
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        switch animationType {
        case .enter:
            enterAnimation(context: transitionContext)
        case .exit:
            exitAnimation(context: transitionContext)
        }
    }
    
}
