//
//  Persistence+SearchHistory.swift
//  Mastodon
//
//  Created by MainasuK on 2022-1-20.
//

import CoreData
import CoreDataStack
import Foundation
import MastodonSDK
import os.log

extension Persistence.SearchHistory {
    
    public struct PersistContext {
        public let entity: Entity
        public let me: MastodonUser
        public let now: Date
        public let log = OSLog.api
        
        public init(
            entity: Entity,
            me: MastodonUser,
            now: Date
        ) {
            self.entity = entity
            self.me = me
            self.now = now
        }
        
        public enum Entity: Hashable {
            case user(MastodonUser)
            case hashtag(Tag)
        }
    }
    
    public struct PersistResult {
        public let searchHistory: SearchHistory
        public let isNewInsertion: Bool
        
        public init(
            searchHistory: SearchHistory,
            isNewInsertion: Bool
        ) {
            self.searchHistory = searchHistory
            self.isNewInsertion = isNewInsertion
        }
    }
    
    public static func createOrMerge(
        in managedObjectContext: NSManagedObjectContext,
        context: PersistContext
    ) -> PersistResult {
        if let old = fetch(in: managedObjectContext, context: context) {
            update(searchHistory: old, context: context)
            return PersistResult(searchHistory: old, isNewInsertion: false)
        } else {
            let object = create(in: managedObjectContext, context: context)
            return PersistResult(searchHistory: object, isNewInsertion: true)
        }
    }
    
}

extension Persistence.SearchHistory {
    
    public static func fetch(
        in managedObjectContext: NSManagedObjectContext,
        context: PersistContext
    ) -> SearchHistory? {
        switch context.entity {
        case .user(let user):
            return user.findSearchHistory(for: context.me)
        case .hashtag(let hashtag):
            return hashtag.findSearchHistory(for: context.me)
        }
    }
    
    @discardableResult
    public static func create(
        in managedObjectContext: NSManagedObjectContext,
        context: PersistContext
    ) -> SearchHistory {
        let property = SearchHistory.Property(
            identifier: UUID(),
            domain: context.me.domain,
            userID: context.me.id,
            createAt: context.now,
            updatedAt: context.now
        )
        let relationship: SearchHistory.Relationship = {
            switch context.entity {
            case .user(let user):
                return SearchHistory.Relationship(account: user, hashtag: nil, status: nil)
            case .hashtag(let hashtag):
                return SearchHistory.Relationship(account: nil, hashtag: hashtag, status: nil)
            }
        }()
        let searchHistory = SearchHistory.insert(
            into: managedObjectContext,
            property: property,
            relationship: relationship
        )
        update(searchHistory: searchHistory, context: context)
        return searchHistory
    }
    
    private static func update(
        searchHistory: SearchHistory,
        context: PersistContext
    ) {
        searchHistory.update(updatedAt: context.now)
    }

}