//
//  ReblogService.swift
//  Tusker
//
//  Created by Shadowfacts on 10/8/22.
//  Copyright © 2022 Shadowfacts. All rights reserved.
//

import UIKit
import Pachyderm

@MainActor
class ReblogService {
    
    private let mastodonController: MastodonController
    private let presenter: any TuskerNavigationDelegate
    private let status: StatusMO
    
    var hapticFeedback = true
    var requireConfirmation = Preferences.shared.confirmBeforeReblog
    
    init(status: StatusMO, mastodonController: MastodonController, presenter: any TuskerNavigationDelegate) {
        self.status = status
        self.mastodonController = mastodonController
        self.presenter = presenter
    }
    
    func toggleReblog() async {
        if !status.reblogged,
           requireConfirmation {
            presentConfirmationAlert()
        } else {
            await doToggleReblog(visibility: nil)
        }
    }
    
    private func presentConfirmationAlert() {
        let image: UIImage?
        let reblogVisibilityActions: [CustomAlertController.MenuAction]
        let maximumVisibility = status.visibility
        if mastodonController.instanceFeatures.reblogVisibility {
            image = UIImage(systemName: maximumVisibility.unfilledImageName)
            reblogVisibilityActions = [Visibility.unlisted, .private].compactMap { visibility in
                guard visibility < maximumVisibility else {
                    return nil
                }
                return CustomAlertController.MenuAction(title: "Reblog as \(visibility.displayName)", subtitle: visibility.subtitle, image: UIImage(systemName: visibility.unfilledImageName)) {
                    // deliberately retain a strong reference to self
                    Task {
                        await self.doToggleReblog(visibility: visibility)
                    }
                }
            }
        } else {
            image = nil
            reblogVisibilityActions = []
        }
        
        let preview = ConfirmReblogStatusPreviewView(status: status)
        var config = CustomAlertController.Configuration(title: "Are you sure you want to reblog this post?", content: preview, actions: [
            CustomAlertController.Action(title: "Cancel", style: .cancel, handler: nil),
            CustomAlertController.Action(title: "Reblog", image: image, style: .default, handler: {
                // deliberately retain a strong reference to self
                Task {
                    await self.doToggleReblog(visibility: nil)
                }
            })
        ])
        if !reblogVisibilityActions.isEmpty {
            var menuAction = CustomAlertController.Action(title: nil, image: UIImage(systemName: "chevron.down"), style: .menu(reblogVisibilityActions), handler: nil)
            menuAction.isSecondaryMenu = true
            config.actions.append(menuAction)
        }
        let alert = CustomAlertController(config: config)
        presenter.present(alert, animated: true)
    }
    
    private func doToggleReblog(visibility: Visibility?) async {
        let oldValue = status.reblogged
        status.reblogged.toggle()
        mastodonController.persistentContainer.statusSubject.send(status.id)
        
        if hapticFeedback {
            UIImpactFeedbackGenerator(style: .light).impactOccurred()
        }
        
        let request: Request<Status>
        if status.reblogged {
            request = Status.reblog(status.id, visibility: visibility)
        } else {
            request = Status.unreblog(status.id)
        }
        do {
            let (newStatus, _) = try await mastodonController.run(request)
            mastodonController.persistentContainer.addOrUpdate(status: newStatus)
        } catch {
            status.favourited = oldValue
            mastodonController.persistentContainer.statusSubject.send(status.id)
            
            let title = oldValue ? "Error Unreblogging" : "Error Reblogging"
            let config = ToastConfiguration(from: error, with: title, in: presenter) { toast in
                toast.dismissToast(animated: true)
                await self.toggleReblog()
            }
            presenter.showToast(configuration: config, animated: true)
            
            if hapticFeedback {
                UINotificationFeedbackGenerator().notificationOccurred(.error)
            }
        }
    }
    
}
