//
//  ReadableDecodingErrors.swift
//  MVMCore
//
//  Created by Kyle Hedden on 10/5/23.
//  Copyright © 2023 myverizon. All rights reserved.
//

import Foundation

protocol HumanReadableDecodingErrorProtocol {
    var readableDescription: String { get }
}

extension JSONError: HumanReadableDecodingErrorProtocol {
    var readableDescription: String {
        switch (self) {
        case .other(let other):
            if let other = other as? HumanReadableDecodingErrorProtocol {
                return other.readableDescription
            }
            return description
        default:
            return description
        }
    }
}

extension ModelRegistry.Error: HumanReadableDecodingErrorProtocol {
    var readableDescription: String {
        switch (self) {
        case .decoderErrorModelNotMapped(let identifier, let codingKey, let codingPath) where identifier != nil && codingKey != nil && codingPath != nil:
            return "Model identifier \"\(identifier!)\" is not mapped for  \"\(codingKey!.stringValue)\" @ \(codingPath!.map { return $0.stringValue })"
            
        case .decoderErrorObjectNotPresent(let codingKey, let codingPath):
            return "Required model \"\(codingKey.stringValue)\" was not found @ \(codingPath.map { return $0.stringValue })"
            
        default:
            return "Registry error: \((self as NSError).localizedFailureReason ?? self.localizedDescription)"
        }
    }
}

extension DecodingError: HumanReadableDecodingErrorProtocol {
    var readableDescription: String {
        switch (self) {
        case .keyNotFound(let codingKey, let context):
            return "Required key \(codingKey.stringValue) was not found @ \(context.codingPath.map { return $0.stringValue })"
            
        case .valueNotFound(_, let context):
            return "Value not found @ \(context.codingPath.map { return $0.stringValue })"
            
        case .typeMismatch(_, let context):
            return "Value type mismatch @ \(context.codingPath.map { return $0.stringValue })"
            
        case .dataCorrupted(let context):
            return "Data corrupted @ \(context.codingPath.map { return $0.stringValue })"
            
        @unknown default:
            return (self as NSError).localizedFailureReason ?? self.localizedDescription
        }
    }
}
