//
//  AstroTestCase.swift
//  Astro
//
//  Created by Jeremy Wiebe on 2015-05-05.
//  Copyright (c) 2015 Mobify Research & Development Inc. All rights reserved.
//

import Foundation
import XCTest

func AssertEqual<T: Equatable>(_ a: T?, b: T?, message: String? = nil) {
    let formattedMessage = message != nil ? " - \(message!)" : ""
    XCTAssert(a == b, "\(a.debugDescription) is not equal to \(b.debugDescription)" + formattedMessage)
}

func AssertEqualType<T: Equatable>(_ a: Any?, b: T?, message: String? = nil) {
    let formattedMessage = message != nil ? " - \(message!)" : ""
    if let a = a as? T {
        XCTAssert(a == b, "\(a) is not equal to \(b.debugDescription)" + formattedMessage)
    } else {
        XCTFail("\(a.debugDescription) is not of type \(T.self)")
    }
}

func AssertEqualArrays<T: Equatable>(_ a: [T], b: [T], message: String? = nil) {
    let formattedMessage = message != nil ? " - \(message!)" : ""
    XCTAssert(a == b, "\(a) is not equal to \(b)" + formattedMessage)
}

func AssertNotNil(_ a: Any?, message: String? = nil) {
    let formattedMessage = message != nil ? " - \(message!)" : ""
    XCTAssert(a != nil, "\(a.debugDescription) is nil" + formattedMessage)
}

func AssertNil(_ a: Any?, message: String? = nil) {
    let formattedMessage = message != nil ? " - \(message!)" : ""
    XCTAssert(a == nil, "\(a.debugDescription) is not nil" + formattedMessage)
}

func testUrl(_ path: String) -> URL {
    return URL(string: "http://localhost:8000/\(path)")!
}

class AstroTestCase: XCTestCase {

    // Helper function you can call in your setUp if your tests require the fixture server
    // Suggested usage: XCTAssertTrue(ensureFixtureServer(), "Fixture server must be running")
    internal func ensureFixtureServer() -> Bool {

        var content: String? = nil
        do {
            content = try String(contentsOf: testUrl("http/200"), encoding: String.Encoding.utf8)
        } catch let error as NSError {
            printFixtureServerFailed(withMessage: "ensureFixtureServer failed with error \(error)")
            return false
        }

        if content != "OK" {
            XCTFail("Fixture server not running")
            let serverUrl = testUrl("")
            printFixtureServerFailed(withMessage: "Make sure the fixture server is listening on: \n\t \(serverUrl)")
            return false
        }

        return true
    }

    fileprivate func printFixtureServerFailed(withMessage message: String) {
        print("=====================================================")
        print("The fixture server does not appear to be running!")
        print("")
        print(message)
        print("")
        print("You can start the server with: npm run fixture-server")
        print("=====================================================")
    }

    func expectAssertion(_ testBlock: (XCTestExpectation) -> Void) {
        let expectation = self.expectation(description: "Assertion was run")

        testBlock(expectation)

        self.waitForExpectations(timeout: 0, handler: nil)
    }

    func expectAssertionWithDelay(_ testBlock: (XCTestExpectation) -> Void) {
        let expectation = self.expectation(description: "Assertion was run")

        testBlock(expectation)

        self.waitForExpectations(timeout: 10) { error in
            XCTAssertNil(error, "Error: \(error!.localizedDescription)")
        }
    }

    func containsChildView(_ parentView: UIView, childView: UIView) -> Bool {
        if parentView == childView {
            return true
        }

        var childViewFound = false
        for subview in parentView.subviews {
            childViewFound = childViewFound || containsChildView(subview, childView: childView)
        }
        return childViewFound
    }
}
