//
//  Created by Tom Baranes on 01/05/16.
//  Copyright © 2016 IBAnimatable. All rights reserved.
//

import UIKit

public class CardsAnimator: NSObject, AnimatedTransitioning {
    // MARK: - AnimatorProtocol

    public var transitionAnimationType: TransitionAnimationType
    public var transitionDuration: Duration = defaultTransitionDuration
    public var reverseAnimationType: TransitionAnimationType?
    public var interactiveGestureType: InteractiveGestureType?

    // MARK: - private

    fileprivate var fromDirection: TransitionAnimationType.Direction

    public init(from direction: TransitionAnimationType.Direction, duration: Duration) {
        transitionDuration = duration
        fromDirection = direction
        transitionAnimationType = .cards(direction: direction)
        reverseAnimationType = .cards(direction: direction.opposite)

        super.init()
    }
}

extension CardsAnimator: UIViewControllerAnimatedTransitioning {
    public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        retrieveTransitionDuration(transitionContext: transitionContext)
    }

    public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let (tempfromView, tempToView, tempContainerView) = retrieveViews(transitionContext: transitionContext)
        guard let fromView = tempfromView, let toView = tempToView, let containerView = tempContainerView else {
            transitionContext.completeTransition(true)
            return
        }

        if fromDirection == .forward {
            executeForwardAnimation(transitionContext: transitionContext, containerView: containerView, fromView: fromView, toView: toView)
        } else {
            executeBackwardAnimation(transitionContext: transitionContext, containerView: containerView, fromView: fromView, toView: toView)
        }
    }
}

// MARK: - Forward

private extension CardsAnimator {
    func executeBackwardAnimation(transitionContext: UIViewControllerContextTransitioning, containerView: UIView, fromView: UIView, toView: UIView) {
        let frame = fromView.frame
        var offScreenFrame = frame
        offScreenFrame.origin.y = offScreenFrame.height
        toView.frame = offScreenFrame
        containerView.insertSubview(toView, aboveSubview: fromView)
        let t1 = firstTransform()
        let t2 = secondTransformWithView(view: fromView)
        UIView.animateKeyframes(withDuration: transitionDuration, delay: 0.0, options: .calculationModeCubic, animations: {
            UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.4) {
                fromView.layer.transform = t1
                fromView.alpha = 0.6
            }

            UIView.addKeyframe(withRelativeStartTime: 0.2, relativeDuration: 0.4) {
                fromView.layer.transform = t2
            }

            UIView.addKeyframe(withRelativeStartTime: 0.6, relativeDuration: 0.2) {
                toView.frame = toView.frame.offsetBy(dx: 0.0, dy: -30.0)
            }

            UIView.addKeyframe(withRelativeStartTime: 0.8, relativeDuration: 0.2) {
                toView.frame = frame
            }

        }) { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}

// MARK: - Reverse

private extension CardsAnimator {
    func executeForwardAnimation(transitionContext: UIViewControllerContextTransitioning, containerView: UIView, fromView: UIView, toView: UIView) {
        let frame = fromView.frame
        toView.frame = frame
        let scale = CATransform3DIdentity
        toView.layer.transform = CATransform3DScale(scale, 0.6, 0.6, 1)
        toView.alpha = 0.6

        containerView.insertSubview(toView, belowSubview: fromView)
        var frameOffScreen = frame
        frameOffScreen.origin.y = frame.height
        let t1 = firstTransform()

        UIView.animateKeyframes(withDuration: transitionDuration, delay: 0.0, options: .calculationModeCubic, animations: {
            UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.5) {
                fromView.frame = frameOffScreen
            }

            UIView.addKeyframe(withRelativeStartTime: 0.35, relativeDuration: 0.35) {
                toView.layer.transform = t1
                toView.alpha = 1.0
            }

            UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) {
                toView.layer.transform = CATransform3DIdentity
            }

        }) { _ in
            if transitionContext.transitionWasCancelled {
                toView.layer.transform = CATransform3DIdentity
                toView.alpha = 1.0
            }
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}

// MARK: - Helper

private extension CardsAnimator {
    func firstTransform() -> CATransform3D {
        var t1 = CATransform3DIdentity
        t1.m34 = 1.0 / -900
        t1 = CATransform3DScale(t1, 0.95, 0.95, 1)
        t1 = CATransform3DRotate(t1, 15.0 * .pi / 180.0, 1, 0, 0)
        return t1
    }

    func secondTransformWithView(view: UIView) -> CATransform3D {
        var t2 = CATransform3DIdentity
        t2.m34 = firstTransform().m34
        t2 = CATransform3DTranslate(t2, 0, view.frame.size.height * -0.08, 0)
        t2 = CATransform3DScale(t2, 0.8, 0.8, 1)
        return t2
    }
}
