import AppKit

// MARK: - Identifiers

extension NSToolbarItem.Identifier {
    static let cardEditBody = Self("card.editBody")
    static let cardRawSource = Self("card.rawSource")
    static let cardAddAttachment = Self("card.addAttachment")
}

// MARK: - The card window's toolbar

/// The card window's toolbar (03-board-ui.md ▸ Toolbar; 05-card-window.md ▸ Window).
///
/// "**Card window default: Edit Body · Raw Source · Add Attachment** — the window's three committed
/// functions, all discoverable from its toolbar; the catalog is the same trio." So the default set
/// *is* the catalog here, and Customize offers rearrangement and removal rather than a choice of
/// items — which is exactly what a window with three functions should offer.
///
/// ### The three items are the three menu rows, predicates included
///
/// - **Edit Body** is "a single toggle button (on-state in Edit — mirroring the View ▸ Edit Body
///   checkmark)", and it disables while source mode is active. That clause is not restated here: the
///   predicate is `EditBodyCommand.isEnabled(body:rawSource:)`, the menu row's own, handed to the
///   item verbatim. The pathfinder's segmented Preview|Edit is retired, so this is one button.
/// - **Raw Source** is "likewise a toggle showing on-state", and its two directions are not
///   symmetric: on enters, off *applies* (`CardRawSourceSession.applyAndLeave`). A refused Apply
///   leaves source mode open, and the item's on-state simply fails to clear — the same way the menu
///   row's checkmark does, because both read `isActive`.
/// - **Add Attachment** "stays enabled in every mode — attachment operations never touch
///   `index.md`, so they're safe alongside a raw edit". Its predicate is likewise the row's own
///   (`AddAttachmentCommand.isEnabled`), which is scope plus the read-only lock and says nothing
///   about the body's mode.
///
/// Labels are the menu titles minus a trailing ellipsis, so File ▸ Add Attachment… labels as **Add
/// Attachment** (03's own example).
@MainActor
enum CardToolbar {

    static let identifier = "dev.rzen.indie.Kanban.card"

    /// "The catalog is the same trio" — so the defaults are the catalog, in 03's order.
    static let defaultItems: [NSToolbarItem.Identifier] = [
        .cardEditBody,
        .cardRawSource,
        .cardAddAttachment,
    ]

    static func specs(
        body: CardBodyPresentation,
        rawSource: CardRawSourceSession,
        attachments: CardAttachments
    ) -> [ToolbarItemSpec] {
        [
            .mirroring(
                menuTitle: "Edit Body",
                identifier: .cardEditBody,
                symbol: "square.and.pencil",
                behavior: .toggle(
                    isEnabled: { [weak body, weak rawSource] in
                        EditBodyCommand.isEnabled(body: body, rawSource: rawSource)
                    },
                    isOn: { [weak body] in body?.mode == .edit },
                    setOn: { [weak body] isOn in body?.setMode(isOn ? .edit : .preview) }
                )
            ),
            .mirroring(
                menuTitle: "Raw Source",
                identifier: .cardRawSource,
                symbol: "doc.plaintext",
                behavior: .toggle(
                    isEnabled: { [weak rawSource] in rawSource != nil },
                    isOn: { [weak rawSource] in rawSource?.isActive == true },
                    setOn: { [weak rawSource] isOn in
                        guard let rawSource else { return }
                        if isOn {
                            rawSource.enter()
                        } else {
                            rawSource.applyAndLeave()
                        }
                    }
                )
            ),
            .mirroring(
                menuTitle: "Add Attachment…",
                identifier: .cardAddAttachment,
                symbol: "paperclip",
                behavior: .button(
                    isEnabled: { [weak attachments] in AddAttachmentCommand.isEnabled(attachments) },
                    perform: { [weak attachments] in attachments?.add() }
                )
            ),
        ]
    }

    static func controller(
        body: CardBodyPresentation,
        rawSource: CardRawSourceSession,
        attachments: CardAttachments
    ) -> WindowToolbarController {
        WindowToolbarController(
            identifier: identifier,
            specs: specs(body: body, rawSource: rawSource, attachments: attachments),
            defaults: defaultItems
        )
    }
}
