//
//  AboutDialog.swift
//  Adwaita
//
//  Created by david-swift on 21.03.24.
//

import CAdw
import Foundation

/// The about dialog widget.
struct AboutDialog: AdwaitaWidget {

    /// Whether the dialog is visible.
    @Binding var visible: Bool
    /// The wrapped view.
    var child: AnyView
    /// The dialog configuration options.
    var config: AdwaitaAboutDialogConfig

    /// The ID for the dialog's storage.
    let dialogID = "dialog"

    /// Initialize the about dialog wrapper.
    /// - Parameters:
    ///     - visible: The visibility.
    ///     - child: The child view.
    ///     - configure: A closure that mutates the dialog configuration.
    init(
        visible: Binding<Bool>,
        child: AnyView,
        configure: (inout AdwaitaAboutDialogConfig) -> Void
    ) {
        self._visible = visible
        self.child = child

        var cfg = AdwaitaAboutDialogConfig()
        configure(&cfg)
        self.config = cfg
    }

    /// The view storage.
    /// - Parameters:
    ///     - modifiers: Modify views before being updated.
    ///     - type: The view render data type.
    /// - Returns: The view storage.
    func container<Data>(data: WidgetData, type: Data.Type) -> ViewStorage where Data: ViewRenderData {
        let storage = child.storage(data: data, type: type)
        update(storage, data: data, updateProperties: true, type: type)
        return storage
    }

    /// Update the stored content.
    /// - Parameters:
    ///     - storage: The storage to update.
    ///     - modifiers: Modify views before being updated
    ///     - updateProperties: Whether to update the view's properties.
    ///     - type: The view render data type.
    func update<Data>(
        _ storage: ViewStorage,
        data: WidgetData,
        updateProperties: Bool,
        type: Data.Type
    ) where Data: ViewRenderData {
        child.updateStorage(storage, data: data, updateProperties: updateProperties, type: type)
        guard updateProperties else {
            return
        }
        if visible {
            if storage.content[dialogID]?.first == nil {
                createDialog(storage: storage)
                adw_dialog_present(
                    storage.content[dialogID]?.first?.opaquePointer?.cast(),
                    storage.opaquePointer?.cast()
                )
            }
            guard let dialog = storage.content[dialogID]?.first?.opaquePointer else {
                return
            }
            config.apply(to: dialog)

            adw_dialog_set_content_height(dialog.cast(), -1)
        } else {
            if storage.content[dialogID]?.first != nil {
                let dialog = storage.content[dialogID]?.first?.opaquePointer
                adw_dialog_close(dialog?.cast())
                storage.content[dialogID] = []
            }
        }
    }

    /// Create a new instance of the dialog.
    /// - Parameter storage: The wrapped view's storage.
    func createDialog(storage: ViewStorage) {
        let pointer = adw_about_dialog_new()
        let dialog = ViewStorage(pointer?.opaque())
        storage.content[dialogID] = [dialog]
        dialog.connectSignal(name: "closed") {
            storage.content[dialogID] = []
            if visible {
                visible = false
            }
        }
    }

}
