//
//  EKEntryView.swift
//  SwiftEntryKit
//
//  Created by Daniel Huri on 4/15/18.
//  Copyright (c) 2018 huri000@gmail.com. All rights reserved.
//

import UIKit

class EKEntryView: EKStyleView {
    
    struct Content {
        var viewController: UIViewController!
        var view: UIView!
        var attributes: EKAttributes
        
        init(viewController: UIViewController, attributes: EKAttributes) {
            self.viewController = viewController
            self.view = viewController.view
            self.attributes = attributes
        }
        
        init(view: UIView, attributes: EKAttributes) {
            self.view = view
            self.attributes = attributes
        }
    }
    
    // MARK: Props
    
    /** Background view */
    private var backgroundView: EKBackgroundView!
    
    /** The content - contains the view, view controller, attributes */
    var content: Content
    
    private lazy var contentView: UIView = {
        return UIView()
    }()
    
    var attributes: EKAttributes {
        return content.attributes
    }
    
    private lazy var contentContainerView: EKStyleView = {
        let contentContainerView = EKStyleView()
        self.addSubview(contentContainerView)
        contentContainerView.layoutToSuperview(axis: .vertically)
        contentContainerView.layoutToSuperview(axis: .horizontally)
        contentContainerView.clipsToBounds = true
        return contentContainerView
    }()

    // MARK: Setup
    init(newEntry content: Content) {
        self.content = content
        super.init(frame: UIScreen.main.bounds)
        setupContentView()
        applyDropShadow()
        applyBackgroundToContentView()
        applyFrameStyle()
        adjustInnerContentAppearanceIfNeeded()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        applyFrameStyle()
    }
    
    func transform(to view: UIView) {
        
        let previousView = content.view
        content.view = view
        view.layoutIfNeeded()
        
        let previousHeight = set(.height, of: frame.height, priority: .must)
        let nextHeight = set(.height, of: view.frame.height, priority: .defaultLow)

        SwiftEntryKit.layoutIfNeeded()
        
        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: [.beginFromCurrentState, .layoutSubviews], animations: {
            
            previousHeight.priority = .defaultLow
            nextHeight.priority = .must
            
            previousView!.alpha = 0

            SwiftEntryKit.layoutIfNeeded()
            
        }, completion: { (finished) in
            
            view.alpha = 0
            
            previousView!.removeFromSuperview()
            self.removeConstraints([previousHeight, nextHeight])

            self.setupContentView()
            
            UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: [.curveEaseOut], animations: {
                view.alpha = 1
            }, completion: nil)
        })
    }
    
    private func setupContentView() {
        contentView.addSubview(content.view)
        content.view.layoutToSuperview(axis: .horizontally)
        content.view.layoutToSuperview(axis: .vertically)
        
        contentContainerView.addSubview(contentView)
        contentView.fillSuperview()
        contentView.layoutToSuperview(axis: .vertically)
        contentView.layoutToSuperview(axis: .horizontally)
    }

    // Complementary logic for issue #117
    private func adjustInnerContentAppearanceIfNeeded() {
        guard let view = content.view as? EntryAppearanceDescriptor else {
            return
        }
        view.bottomCornerRadius = attributes.roundCorners.cornerValues?.radius ?? 0
    }
    
    // Apply round corners
    private func applyFrameStyle() {
        backgroundView.applyFrameStyle(roundCorners: attributes.roundCorners, border: attributes.border)
    }
    
    // Apply drop shadow
    private func applyDropShadow() {
        switch attributes.shadow {
        case .active(with: let value):
            applyDropShadow(withOffset: value.offset,
                            opacity: value.opacity,
                            radius: value.radius,
                            color: value.color.color(for: traitCollection, mode: attributes.displayMode))
        case .none:
            removeDropShadow()
        }
    }
    
    // Apply background
    private func applyBackgroundToContentView() {
        let attributes = content.attributes
        
        let backgroundView = EKBackgroundView()
        backgroundView.style = .init(background: attributes.entryBackground,
                                     displayMode: attributes.displayMode)
        
        switch attributes.positionConstraints.safeArea {
        case .empty(fillSafeArea: let fillSafeArea) where fillSafeArea: // Safe area filled with color
            insertSubview(backgroundView, at: 0)
            backgroundView.layoutToSuperview(axis: .horizontally)
            
            var topInset: CGFloat = 0
            var bottomInset: CGFloat = 0
            switch attributes.position {
            case .top:
                topInset = -EKWindowProvider.safeAreaInsets.top
            case .bottom, .center:
                bottomInset = EKWindowProvider.safeAreaInsets.bottom
            }
            
            backgroundView.layoutToSuperview(.top, offset: topInset)
            backgroundView.layoutToSuperview(.bottom, offset: bottomInset)
        default: // Float case or a Toast with unfilled safe area
            contentView.insertSubview(backgroundView, at: 0)
            backgroundView.fillSuperview()
        }
        
        self.backgroundView = backgroundView
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        applyDropShadow()
    }
}
