//
//  MastodonMenu.swift
//  
//
//  Created by MainasuK on 2022-1-26.
//

import UIKit
import MastodonLocalization

public protocol MastodonMenuDelegate: AnyObject {
    func menuAction(_ action: MastodonMenu.Action)
}

public enum MastodonMenu {
    public static func setupMenu(
        actions: [Action],
        delegate: MastodonMenuDelegate
    ) -> UIMenu {
        var children: [UIMenuElement] = []
        for action in actions {

            let element: UIMenuElement
            
            if case let .deleteStatus = action {
                let deleteAction = action.build(delegate: delegate).menuElement
                element = UIMenu(options: .displayInline, children: [deleteAction])
            } else {
                element = action.build(delegate: delegate).menuElement
            }
            children.append(element)
        }
        return UIMenu(children: children)
    }

    public static func setupAccessibilityActions(
        actions: [Action],
        delegate: MastodonMenuDelegate
    ) -> [UIAccessibilityCustomAction] {
        var accessibilityActions: [UIAccessibilityCustomAction] = []
        for action in actions {
            let element = action.build(delegate: delegate)
            accessibilityActions.append(element.accessibilityCustomAction)
        }
        return accessibilityActions
    }
}

extension MastodonMenu {
    public enum Action {
        case translateStatus(TranslateStatusActionContext)
        case muteUser(MuteUserActionContext)
        case blockUser(BlockUserActionContext)
        case reportUser(ReportUserActionContext)
        case shareUser(ShareUserActionContext)
        case bookmarkStatus(BookmarkStatusActionContext)
        case hideReblogs(HideReblogsActionContext)
        case shareStatus
        case deleteStatus
        case editStatus
        
        func build(delegate: MastodonMenuDelegate) -> LabeledAction {
            switch self {
            case .hideReblogs(let context):
                let title = context.showReblogs ? L10n.Common.Controls.Friendship.hideReblogs : L10n.Common.Controls.Friendship.showReblogs
                let reblogAction = LabeledAction(title: title, image: UIImage(systemName: "arrow.2.squarepath")) { [weak delegate] in
                    guard let delegate = delegate else { return }
                    delegate.menuAction(self)
                }

                return reblogAction
            case .muteUser(let context):
                let title: String
                let image: UIImage?
                if context.isMuting {
                    title = L10n.Common.Controls.Friendship.unmuteUser(context.name)
                    image = UIImage(systemName: "speaker.wave.2")
                } else {
                    title = L10n.Common.Controls.Friendship.muteUser(context.name)
                    image = UIImage(systemName: "speaker.slash")
                }
                let muteAction = LabeledAction(title: title, image: image) { [weak delegate] in
                    guard let delegate = delegate else { return }
                    delegate.menuAction(self)
                }
                return muteAction
            case .blockUser(let context):
                let title: String
                let image: UIImage?
                if context.isBlocking {
                    title = L10n.Common.Controls.Friendship.unblockUser(context.name)
                    image = UIImage(systemName: "hand.raised.slash")
                } else {
                    title = L10n.Common.Controls.Friendship.blockUser(context.name)
                    image = UIImage(systemName: "hand.raised")
                }
                let blockAction = LabeledAction(title: title, image: image) { [weak delegate] in
                    guard let delegate = delegate else { return }
                    delegate.menuAction(self)
                }
                return blockAction
            case .reportUser(let context):
                let reportAction = LabeledAction(
                    title: L10n.Common.Controls.Actions.reportUser(context.name),
                    image: UIImage(systemName: "flag")
                ) { [weak delegate] in
                    guard let delegate = delegate else { return }
                    delegate.menuAction(self)
                }
                return reportAction
            case .shareUser(let context):
                let shareAction = LabeledAction(
                    title: L10n.Common.Controls.Actions.shareUser(context.name),
                    image: UIImage(systemName: "square.and.arrow.up")
                ) { [weak delegate] in
                    guard let delegate = delegate else { return }
                    delegate.menuAction(self)
                }
                return shareAction
            case .bookmarkStatus(let context):
                let title: String
                let image: UIImage?
                if context.isBookmarking {
                    title = "Remove Bookmark" // TODO: i18n
                    image = UIImage(systemName: "bookmark.slash.fill")
                } else {
                    title = "Bookmark" // TODO: i18n
                    image = UIImage(systemName: "bookmark")
                }
                let action = LabeledAction(title: title, image: image) { [weak delegate] in
                    guard let delegate = delegate else { return }
                    delegate.menuAction(self)
                }
                return action
            case .shareStatus:
                let action = LabeledAction(
                    title: "Share",      // TODO: i18n
                    image: UIImage(systemName: "square.and.arrow.up")
                ) { [weak delegate] in
                    guard let delegate = delegate else { return }
                    delegate.menuAction(self)
                }
                return action
            case .deleteStatus:
                let deleteAction = LabeledAction(
                    title: L10n.Common.Controls.Actions.delete,
                    image: UIImage(systemName: "minus.circle"),
                    attributes: .destructive
                ) { [weak delegate] in
                    guard let delegate = delegate else { return }
                    delegate.menuAction(self)
                }
                return deleteAction
            case let .translateStatus(context):
                let language = Locale.current.localizedString(forIdentifier: context.language) ?? L10n.Common.Controls.Actions.TranslatePost.unknownLanguage
                let translateAction = LabeledAction(
                    title: L10n.Common.Controls.Actions.TranslatePost.title(language),
                    image: UIImage(systemName: "character.book.closed")
                ) { [weak delegate] in
                    guard let delegate = delegate else { return }
                    delegate.menuAction(self)
                }
                return translateAction
            case .editStatus:
                let editStatusAction = BuiltAction(title: L10n.Common.Controls.Actions.editPost, image: UIImage(systemName: "pencil")) {
                    [weak delegate] in
                    guard let delegate else { return }
                    delegate.menuAction(self)
                }

                return editStatusAction
            }   // end switch
        }   // end func build
    }   // end enum Action
}

extension MastodonMenu {
    public struct MuteUserActionContext {
        public let name: String
        public let isMuting: Bool
        
        public init(name: String, isMuting: Bool) {
            self.name = name
            self.isMuting = isMuting
        }
    }
    
    public struct BlockUserActionContext {
        public let name: String
        public let isBlocking: Bool
        
        public init(name: String, isBlocking: Bool) {
            self.name = name
            self.isBlocking = isBlocking
        }
    }
    
    public struct BookmarkStatusActionContext {
        public let isBookmarking: Bool
        
        public init(isBookmarking: Bool) {
            self.isBookmarking = isBookmarking
        }
    }
    
    public struct ReportUserActionContext {
        public let name: String
        
        public init(name: String) {
            self.name = name
        }
    }
    
    public struct ShareUserActionContext {
        public let name: String
        
        public init(name: String) {
            self.name = name
        }
    }

    public struct HideReblogsActionContext {
        public let showReblogs: Bool

        public init(showReblogs: Bool) {
            self.showReblogs = showReblogs
        }
    }
    
    public struct TranslateStatusActionContext {
        public let language: String
        
        public init(language: String) {
            self.language = language
        }
    }
}
