//
//  NSManagedContext+Extensions.swift
//  LeCountdown
//
//  Created by Laurent Morvillier on 24/01/2023.
//

import Foundation
import CoreData

extension NSManagedObjectContext {
    
    func object(stringId: String) -> NSManagedObject? {
        guard let url = URL(string: stringId) else { return nil }
        guard let objectId = PersistenceController.shared.container.persistentStoreCoordinator.managedObjectID(forURIRepresentation: url) else { return nil }
        return self.object(with: objectId)
    }
        
    func compute(activity: Activity, stats: [Stat]) throws -> [StatValue] {
        
        // Step 1:
        // - Create the summing expression on the amount attribute.
        // - Name the expression result as 'amountTotal'.
        // - Assign the expression result data type as a Double.
        
        var expressions: [NSExpressionDescription] = []
        
        for stat in stats {
            let expression = NSExpressionDescription()
            expression.expression = NSExpression(forFunction: stat.function, arguments:[NSExpression(forKeyPath: stat.field)])
            expression.name = stat.stringIdentifier;
            expression.expressionResultType = NSAttributeType.doubleAttributeType
            
            expressions.append(expression)
        }
        
        // Step 2:
        // - Create the fetch request for the Movement entity.
        // - Indicate that the fetched properties are those that were
        //   described in `expression`.
        // - Indicate that the result type is a dictionary.
        
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Record")
        fetchRequest.predicate = NSPredicate(format: "activity = %@", activity)
        fetchRequest.propertiesToFetch = expressions
        fetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType
        
        // Step 3:
        // - Execute the fetch request which returns an array.
        // - There will only be one result. Get the first array
        //   element and assign to 'resultMap'.
        // - The summed amount value is in the dictionary as
        //   'amountTotal'. This will be summed value.
        
        var statValues: [StatValue] = []
        
        let results = try self.fetch(fetchRequest)
        if let resultMap = results.first as? [String : Any] {
            
            for stat in stats {
                
                if let result = resultMap[stat.stringIdentifier] {
                    
                    var value: NSDecimalNumber? = nil
                    switch result {
                    case let double as Double:
                        value = NSDecimalNumber(value: double)
                    case let integer as Int:
                        value = NSDecimalNumber(integerLiteral: integer)
                    default:
                        print("unmanaged value type = \(String(describing: result))")
                        break
                    }
                    
                    if let value {
                        let sv = StatValue(stat: stat, value: value)
                        statValues.append(sv)
                    }
                }
            }
        }
        return statValues
    }
}

extension NSManagedObject {
    
    var isTemporary: Bool {
        return self.objectID.isTemporaryID
    }
    
    var stringId: String {
        return self.objectID.uriRepresentation().absoluteString
    }
    
}
