import XCTest
@testable import Wikipedia

class MeasurableArticlePeekPreviewViewController: ArticlePeekPreviewViewController {
    var displayCompletion: (() -> Void)?
    
    override func updatePreferredContentSize(for contentWidth: CGFloat) {
        super.updatePreferredContentSize(for: contentWidth)
        displayCompletion?()
    }
}

class ArticleManualPerformanceTests: XCTestCase {
    let timeout: TimeInterval = 10
    
    private var articleURL: URL! = URL(string: "https://en.wikipedia.org/wiki/Dog")
    private var appSchemeArticleURL: URL! = URL(string: "app://en.wikipedia.org/wiki/Dog")
    private var contextMenuConfigAppSchemeArticleURL: URL! = URL(string: "app://en.wikipedia.org/wiki/Cat")
    
    override func setUp() {
        super.setUp()
        
        LSNocilla.sharedInstance().start()
        ArticleTestHelpers.stubCompleteMobileHTMLResponse(inBundle: wmf_bundle())
    }

    override func tearDown() {
        super.tearDown()
        LSNocilla.sharedInstance().stop()
    }

    // represents the speed at which article content is seen on screen
    func testArticleSetupTime() {

        self.measure {
            
            let dataStore = MWKDataStore.temporary()
            guard let articleVC = ArticleViewController(articleURL: articleURL, dataStore: dataStore, theme: .light) else {
                XCTFail("Unable to instantiate ArticleViewController")
                return
            }
            
            let setupExpectation = expectation(description: "Waiting for article initial setup call")
            
            articleVC.initialSetupCompletion = {
                setupExpectation.fulfill()
                UIApplication.shared.workaroundKeyWindow?.rootViewController = nil
                dataStore.clearTemporaryCache()
            }
            
            UIApplication.shared.workaroundKeyWindow?.rootViewController = articleVC
        
            wait(for: [setupExpectation], timeout: timeout)
        }
    }
    
    // represents the speed at which the context menu configuration is generated from a 3D touch on an article link
    func testContextMenuConfigTime() {
        
        let dataStore = MWKDataStore.temporary()
        self.measure {
            
            guard let articleVC = ArticleViewController(articleURL: articleURL, dataStore: dataStore, theme: .light) else {
                XCTFail("Unable to instantiate ArticleViewController")
                return
            }
            
            let contextExpectation = expectation(description: "Waiting for context menu configuration call")
            
            articleVC.contextMenuConfigurationForLinkURL(contextMenuConfigAppSchemeArticleURL, ignoreTimeout: true) { (completionType, menuConfig) in
                if completionType == .bail {
                   XCTFail("Menu config should not bail.")
                }
                
                if completionType == .timeout {
                    XCTFail("Menu config should not time out.")
                }
                
                contextExpectation.fulfill()
                dataStore.clearTemporaryCache()
            }
        
            wait(for: [contextExpectation], timeout: timeout)
        }
    }
    
    func testArticlePeekPreviewControllerDisplayTime() {
        
        let dataStore = MWKDataStore.temporary()
        
        self.measure {
        
            let peekVC = MeasurableArticlePeekPreviewViewController(articleURL: articleURL, dataStore: dataStore, theme: .standard)
            
            let displayExpectation = expectation(description: "Waiting for MeasurableArticlePeekPreviewViewController displayCompletion call")
            
            peekVC.displayCompletion = {
                displayExpectation.fulfill()
                UIApplication.shared.workaroundKeyWindow?.rootViewController = nil
                dataStore.clearTemporaryCache()
            }
            
            UIApplication.shared.workaroundKeyWindow?.rootViewController = peekVC
            
            wait(for: [displayExpectation], timeout: timeout)
        }
    }
}
