//
//  GamesStoryboardSegue.swift
//  Delta
//
//  Created by Riley Testut on 8/7/16.
//  Copyright © 2016 Riley Testut. All rights reserved.
//

import UIKit

class GamesStoryboardSegue: UIStoryboardSegue
{
    private let animator: UIViewPropertyAnimator
    
    private var isPresenting: Bool = true
    
    override init(identifier: String?, source: UIViewController, destination: UIViewController)
    {
        let timingParameters = UISpringTimingParameters(mass: 3.0, stiffness: 750, damping: 65, initialVelocity: CGVector(dx: 0, dy: 0))
        self.animator = UIViewPropertyAnimator(duration: 0, timingParameters: timingParameters)
        
        super.init(identifier: identifier, source: source, destination: destination)
    }
    
    override func perform()
    {
        self.destination.transitioningDelegate = self
        self.destination.modalPresentationStyle = .custom
        self.destination.modalPresentationCapturesStatusBarAppearance = true
        
        super.perform()
    }
}

extension GamesStoryboardSegue: UIViewControllerTransitioningDelegate
{
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?
    {
        self.isPresenting = true
        return self
    }
    
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
    {
        self.isPresenting = false
        return self
    }
    
    func presentationController(forPresented presentedViewController: UIViewController, presenting presentingViewController: UIViewController?, source: UIViewController) -> UIPresentationController?
    {
        let presentationController = GamesPresentationController(presentedViewController: presentedViewController, presenting: presentingViewController, animator: self.animator)
        return presentationController
    }
}

extension GamesStoryboardSegue: UIViewControllerAnimatedTransitioning
{
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval
    {
        return self.animator.duration
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
    {
        if self.isPresenting
        {
            self.animatePresentationTransition(using: transitionContext)
        }
        else
        {
            self.animateDismissalTransition(using: transitionContext)
        }
    }
    
    func animatePresentationTransition(using transitionContext: UIViewControllerContextTransitioning)
    {
        transitionContext.sourceViewController.beginAppearanceTransition(false, animated: true)
        
        transitionContext.destinationView.clipsToBounds = false
        transitionContext.destinationView.frame = transitionContext.destinationViewFinalFrame!
        transitionContext.destinationView.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)
        transitionContext.containerView.addSubview(transitionContext.destinationView)
        
        let snapshotView = transitionContext.sourceView.snapshotView(afterScreenUpdates: false)!
        snapshotView.frame = transitionContext.sourceViewInitialFrame!
        snapshotView.alpha = 1.0
        transitionContext.containerView.addSubview(snapshotView)
        
        // We add extra padding around the existing navigation bar and toolbar so they never appear to be detached from the edges of the screen during the overshooting of the spring animation
        var topPaddingToolbar: UIToolbar? = nil
        var bottomPaddingToolbar: UIToolbar? = nil
        
        // Must be wrapped in no-animation block to prevent iOS 11 search bar from not appearing.
        UIView.performWithoutAnimation {
            // Ensures navigation controller toolbar (if visible) has been added to view heirachy, allowing us to add constraints
            transitionContext.containerView.layoutIfNeeded()
            
            if let navigationController = transitionContext.destinationViewController as? UINavigationController
            {
                let padding: CGFloat = 44
                let topViewController = navigationController.viewControllers[0]
                
                if !navigationController.isNavigationBarHidden
                {
                    let topToolbar = UIToolbar(frame: CGRect.zero)
                    topToolbar.translatesAutoresizingMaskIntoConstraints = false
                    topToolbar.barStyle = navigationController.toolbar.barStyle
                    transitionContext.destinationView.insertSubview(topToolbar, at: 1)
                    
                    if #available(iOS 13, *)
                    {
                        let appearance = UIToolbarAppearance(barAppearance: navigationController.navigationBar.standardAppearance)
                        topToolbar.standardAppearance = appearance
                        
                        topToolbar.topAnchor.constraint(equalTo: topViewController.view.topAnchor, constant: -padding).isActive = true
                        topToolbar.leftAnchor.constraint(equalTo: topViewController.view.leftAnchor, constant: -padding).isActive = true
                        topToolbar.rightAnchor.constraint(equalTo: topViewController.view.rightAnchor, constant: padding).isActive = true
                        topToolbar.bottomAnchor.constraint(equalTo: topViewController.view.safeAreaLayoutGuide.topAnchor).isActive = true
                    }
                    else
                    {
                        topToolbar.topAnchor.constraint(equalTo: navigationController.navigationBar.topAnchor, constant: -padding).isActive = true
                        topToolbar.leftAnchor.constraint(equalTo: navigationController.navigationBar.leftAnchor, constant: -padding).isActive = true
                        topToolbar.rightAnchor.constraint(equalTo: navigationController.navigationBar.rightAnchor, constant: padding).isActive = true
                        
                        // There is no easy way to determine the extra height necessary at this point of the transition, so hard code for now.
                        let additionalSearchBarHeight = 44 as CGFloat
                        topToolbar.heightAnchor.constraint(equalToConstant: navigationController.topViewController!.view.safeAreaInsets.top + additionalSearchBarHeight).isActive = true
                    }
                    
                    topPaddingToolbar = topToolbar
                }
                
                if !navigationController.isToolbarHidden
                {
                    let bottomToolbar = UIToolbar(frame: CGRect.zero)
                    bottomToolbar.translatesAutoresizingMaskIntoConstraints = false
                    bottomToolbar.barStyle = navigationController.toolbar.barStyle
                    transitionContext.destinationView.insertSubview(bottomToolbar, belowSubview: navigationController.navigationBar)
                    
                    if #available(iOS 13, *)
                    {
                        let appearance = UIToolbarAppearance(barAppearance: navigationController.toolbar.standardAppearance)
                        bottomToolbar.standardAppearance = appearance
                        
                        bottomToolbar.topAnchor.constraint(equalTo: topViewController.view.safeAreaLayoutGuide.bottomAnchor).isActive = true
                        bottomToolbar.bottomAnchor.constraint(equalTo: topViewController.view.bottomAnchor, constant: padding).isActive = true
                        bottomToolbar.leftAnchor.constraint(equalTo: topViewController.view.leftAnchor, constant: -padding).isActive = true
                        bottomToolbar.rightAnchor.constraint(equalTo: topViewController.view.rightAnchor, constant: padding).isActive = true
                    }
                    else
                    {
                        bottomToolbar.topAnchor.constraint(equalTo: navigationController.toolbar.topAnchor).isActive = true
                        bottomToolbar.bottomAnchor.constraint(equalTo: navigationController.toolbar.bottomAnchor, constant: padding).isActive = true
                        bottomToolbar.leftAnchor.constraint(equalTo: navigationController.toolbar.leftAnchor, constant: -padding).isActive = true
                        bottomToolbar.rightAnchor.constraint(equalTo: navigationController.toolbar.rightAnchor, constant: padding).isActive = true
                    }
                    
                    bottomPaddingToolbar = bottomToolbar
                }
            }
        }
        
        self.animator.addAnimations {
            snapshotView.alpha = 0.0
            transitionContext.destinationView.transform = CGAffineTransform.identity
        }
        
        self.animator.addCompletion { (position) in
            transitionContext.completeTransition(position == .end)
            
            snapshotView.removeFromSuperview()
            
            topPaddingToolbar?.removeFromSuperview()
            bottomPaddingToolbar?.removeFromSuperview()
            
            transitionContext.sourceViewController.endAppearanceTransition()
        }
        
        self.animator.startAnimation()
    }
    
    func animateDismissalTransition(using transitionContext: UIViewControllerContextTransitioning)
    {
        transitionContext.destinationViewController.beginAppearanceTransition(true, animated: true)
        
        self.animator.addAnimations {
            transitionContext.sourceView.alpha = 0.0
            transitionContext.sourceView.transform = CGAffineTransform(scaleX: 2.0, y: 2.0)
        }
        
        self.animator.addCompletion { (position) in
            transitionContext.completeTransition(position == .end)
            transitionContext.destinationViewController.endAppearanceTransition()
        }
        
        self.animator.startAnimation()
    }
}

