//
//  BatchUpdatesTest.swift
//  PascalTests
//
//  Created by Helena McGahagan on 1/10/20.
//  Copyright © 2020 Evidation Health, Inc. All rights reserved.
//

import XCTest
@testable import EvidationCommonUI

class BatchUpdatesTest: EvidationCommonUITests {

    static let numberOfRandomTests = 100
    static let maximumLengthOfValues = 10
    
    override func setUp() {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testBatchUpdates() {
        (0...BatchUpdatesTest.numberOfRandomTests).forEach {_ in BatchUpdatesTest.randomTest() }
    }
    
    static func randomTest() {
        let range = 0..<BatchUpdatesTest.maximumLengthOfValues
        let length1 = Int.random(in: range)
        let length2 = Int.random(in: range)
        
        var values1 = Array(range)
        var values2 = Array(range)
        
        // Remove length1 random values for the values1 array
        (0...length1).forEach {_ in
            let range = 0..<values1.count
            let index = Int.random(in: range)
            values1.remove(at: index)
        }
        // Remove length2 random values for the values2 array
        (0...length2).forEach {_ in
            let range = 0..<values2.count
            let index = Int.random(in: range)
            values2.remove(at: index)
        }
        // Shuffle the values
        values1 = shuffle(values1)
        values2 = shuffle(values2)
        
        // Compute batch updates to transition from values1->values2
        let updates = BatchUpdates.compare(oldValues: values1, newValues: values2)
        
        // Check that all indexes in values1 are accounted for (and not dobule counted)
        //  in the delete, reload, and move operations
        let fromIndices = updates.deleted + updates.reloaded + updates.moved.map { $0.0 }
        XCTAssertEqual(fromIndices.sorted { $0 < $1 }, Array(0..<values1.count))
        
        // Check that all indexes in values2 are accounted for (and not dobule counted)
        //  in the insert, reload, and move operations
        let toIndices = updates.inserted + updates.reloaded + updates.moved.map { $0.1 }
        XCTAssertEqual(toIndices.sorted { $0 < $1 }, Array(0..<values2.count))
    }
    
    static private func shuffle(_ array: [Int]) -> [Int] {
        guard !array.isEmpty else { return [] }
        
        var newArray: [Int] = []

        var remainingValues = array
        while !remainingValues.isEmpty {
            let range = 0..<remainingValues.count
            let index = Int.random(in: range)
            let value = remainingValues.remove(at: index)
            newArray.append(value)
        }
        
        return newArray
    }

}
