//
//  FilterMO.swift
//  Tusker
//
//  Created by Shadowfacts on 11/30/22.
//  Copyright © 2022 Shadowfacts. All rights reserved.
//

import Foundation
import CoreData
import Pachyderm

@objc(FilterMO)
public final class FilterMO: NSManagedObject {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<FilterMO> {
        return NSFetchRequest(entityName: "Filter")
    }
    
    @nonobjc public class func fetchRequest(id: String) -> NSFetchRequest<FilterMO> {
        let req = NSFetchRequest<FilterMO>(entityName: "Filter")
        req.predicate = NSPredicate(format: "id = %@", id)
        return req
    }
    
    @NSManaged public var id: String
    @NSManaged public var title: String?
    @NSManaged private var context: String
    @NSManaged public var expiresAt: Date?
    @NSManaged public var keywords: NSMutableSet
    @NSManaged public var action: String
    
    private var _contexts: [FilterV1.Context]?
    public var contexts: [FilterV1.Context] {
        get {
            if let _contexts {
                return _contexts
            } else {
                _contexts = context.split(separator: ",").compactMap { .init(rawValue: String($0)) }
                return _contexts!
            }
        }
        set {
            _contexts = newValue
            context = newValue.map(\.rawValue).joined(separator: ",")
        }
    }
    
    var keywordMOs: [FilterKeywordMO] {
        keywords.allObjects as! [FilterKeywordMO]
    }
    
    var titleOrKeyword: String {
        title ?? (keywords.allObjects.first! as! FilterKeywordMO).keyword
    }
    
    var filterAction: FilterV2.Action {
        get {
            FilterV2.Action(rawValue: action)!
        }
        set {
            action = newValue.rawValue
        }
    }
    
    public override func didChangeValue(forKey key: String) {
        super.didChangeValue(forKey: key)
        if key == "context" {
            _contexts = nil
        }
    }
    
}

extension FilterMO {
    func updateFrom(apiFilter filter: AnyFilter, context: NSManagedObjectContext) {
        switch filter {
        case .v1(let v1):
            self.updateFrom(apiFilter: v1, context: context)
        case .v2(let v2):
            self.updateFrom(apiFilter: v2, context: context)
        }
    }
    
    func updateFrom(apiFilter filter: FilterV1, context: NSManagedObjectContext) {
        self.id = filter.id
        self.title = nil
        self.contexts = filter.contexts
        self.expiresAt = filter.expiresAt
        self.filterAction = .warn
        let keyword: FilterKeywordMO
        if self.keywords.count == 0 {
            keyword = FilterKeywordMO(context: context)
            keyword.filter = self
            self.keywords.add(keyword)
        } else {
            keyword = self.keywords.allObjects.first! as! FilterKeywordMO
        }
        keyword.keyword = filter.phrase
        keyword.wholeWord = filter.wholeWord
        keyword.id = nil
    }
    
    func updateFrom(apiFilter filter: FilterV2, context: NSManagedObjectContext) {
        self.id = filter.id
        self.title = filter.title
        self.contexts = filter.context
        self.expiresAt = filter.expiresAt
        self.filterAction = filter.action
        
        var existing = keywordMOs
        for keyword in filter.keywords {
            if let mo = existing.first(where: { $0.id == keyword.id }) {
                mo.updateFrom(apiKeyword: keyword)
                existing.removeAll(where: { $0.id == keyword.id })
            } else {
                let mo = FilterKeywordMO(context: context)
                mo.updateFrom(apiKeyword: keyword)
                mo.filter = self
                self.keywords.add(mo)
            }
        }
        for unupdated in existing {
            context.delete(unupdated)
        }
    }
}

enum AnyFilter {
    case v1(FilterV1)
    case v2(FilterV2)
    
    var id: String {
        switch self {
        case .v1(let v1):
            return v1.id
        case .v2(let v2):
            return v2.id
        }
    }
}
