//
//  PopoverMessageViewController.swift
//
//  Copyright © 2021 DuckDuckGo. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

import AppKit
import SwiftUI
import SwiftUIExtensions
final class PopoverMessageViewController: NSHostingController<PopoverMessageView>, NSPopoverDelegate {

    enum Constants {
        static let storyboardName = "MessageViews"
        static let identifier = "PopoverMessageView"
        static let autoDismissDuration: TimeInterval = 2.5
    }

    let viewModel: PopoverMessageViewModel
    let onDismiss: (() -> Void)?
    let autoDismissDuration: TimeInterval?
    let onClick: (() -> Void)?
    private var timer: Timer?
    private var trackingArea: NSTrackingArea?

    init(title: String? = nil,
         message: String,
         image: NSImage? = nil,
         buttonText: String? = nil,
         buttonAction: (() -> Void)? = nil,
         shouldShowCloseButton: Bool = false,
         presentMultiline: Bool = false,
         autoDismissDuration: TimeInterval? = Constants.autoDismissDuration,
         onDismiss: (() -> Void)? = nil,
         onClick: (() -> Void)? = nil) {
        self.viewModel = PopoverMessageViewModel(title: title,
                                                 message: message,
                                                 image: image,
                                                 buttonText: buttonText,
                                                 buttonAction: buttonAction,
                                                 shouldShowCloseButton: shouldShowCloseButton,
                                                 shouldPresentMultiline: presentMultiline)
        self.onDismiss = onDismiss
        self.autoDismissDuration = autoDismissDuration
        self.onClick = onClick
        let contentView = PopoverMessageView(viewModel: self.viewModel, onClick: { }, onClose: { })
        super.init(rootView: contentView)
        self.rootView = createContentView()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    deinit {
        cancelAutoDismissTimer()

        if let trackingArea = trackingArea {
            view.removeTrackingArea(trackingArea)
        }
        onDismiss?()
    }

    override func viewDidAppear() {
        super.viewDidAppear()
        createTrackingArea()
        scheduleAutoDismissTimer()
    }

    func show(onParent parent: NSViewController, rect: NSRect, of view: NSView, preferredEdge: NSRectEdge = .maxY) {
        // Set the content size to match the SwiftUI view's intrinsic size
        self.preferredContentSize = self.view.fittingSize
        // For shorter strings, the positioning can be off unless the width is set a second time
        self.preferredContentSize.width = self.view.fittingSize.width

        parent.present(self,
                       asPopoverRelativeTo: rect,
                       of: view,
                       preferredEdge: preferredEdge,
                       behavior: .applicationDefined)
    }

    func show(onParent parent: NSViewController,
              relativeTo view: NSView,
              preferredEdge: NSRectEdge = .maxY,
              behavior: NSPopover.Behavior = .applicationDefined) {
        // Set the content size to match the SwiftUI view's intrinsic size
        self.preferredContentSize = self.view.fittingSize
        // For shorter strings, the positioning can be off unless the width is set a second time
        self.preferredContentSize.width = self.view.fittingSize.width

        parent.present(self,
                       asPopoverRelativeTo: self.view.bounds,
                       of: view,
                       preferredEdge: preferredEdge,
                       behavior: behavior)
    }

    // MARK: - Auto Dismissal
    private func cancelAutoDismissTimer() {
        timer?.invalidate()
        timer = nil
    }

    private func scheduleAutoDismissTimer() {
        cancelAutoDismissTimer()
        if let autoDismissDuration {
            timer = Timer.scheduledTimer(withTimeInterval: autoDismissDuration, repeats: false) { [weak self] _ in
                guard let self = self else { return }
                self.presentingViewController?.dismiss(self)
            }
        }
    }

    // MARK: - Mouse Tracking
    private func createTrackingArea() {
        trackingArea = NSTrackingArea(rect: view.bounds,
                                      options: [.mouseEnteredAndExited, .activeInKeyWindow],
                                      owner: self,
                                    userInfo: nil)
        view.addTrackingArea(trackingArea!)
    }

    override func mouseEntered(with event: NSEvent) {
        cancelAutoDismissTimer()
    }

    override func mouseExited(with event: NSEvent) {
        scheduleAutoDismissTimer()
    }

    override func mouseDown(with event: NSEvent) {
        onClick?()
        dismissPopover()
    }

    private func dismissPopover() {
        presentingViewController?.dismiss(self)
    }

    private func createContentView() -> PopoverMessageView {
        return PopoverMessageView(viewModel: self.viewModel, onClick: { [weak self] in
            self?.onClick?()
        }) { [weak self] in
            self?.dismissPopover()
        }
    }
}