//
//  BeamNSTableView.swift
//  Beam
//
//  Created by Remi Santos on 13/04/2021.
//

import Foundation

protocol BeamNSTableViewDelegate: AnyObject {
    func tableViewDidChangeEffectiveAppearance(_ tableView: BeamNSTableView)
    func tableView(_ tableView: BeamNSTableView, mouseDownFor row: Int, column: Int, locationInWindow: NSPoint, modifiers: NSEvent.ModifierFlags) -> Bool
    func tableView(_ tableView: BeamNSTableView, rightMouseDownFor row: Int, column: Int, locationInWindow: NSPoint)
    func tableView(_ tableView: BeamNSTableView, didDoubleTap row: Int)
}

class BeamNSTableView: NSTableView {

    weak var additionalDelegate: BeamNSTableViewDelegate?

    var onHoverTableView: ((_ hovering: Bool) -> Void)?

    init() {
        super.init(frame: .zero)
        self.target = self
        self.doubleAction = #selector(didDoubleSelectRow)
    }

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

    override func viewDidChangeEffectiveAppearance() {
        super.viewDidChangeEffectiveAppearance()
        additionalDelegate?.tableViewDidChangeEffectiveAppearance(self)
    }

    private func rowAndColumnForWindowLocation(_ locationInWindow: NSPoint) -> (Int, Int)? {
        let localLocation = convert(locationInWindow, from: nil)
        let row = self.row(at: localLocation)
        let column = self.column(at: localLocation)
        guard row >= 0 && column >= 0 else { return nil }
        return (row, column)
    }

    override func rightMouseDown(with event: NSEvent) {
        super.rightMouseDown(with: event)
        guard let additionalDelegate = additionalDelegate,
              let (row, column) = rowAndColumnForWindowLocation(event.locationInWindow)
        else { return }
        additionalDelegate.tableView(self, rightMouseDownFor: row, column: column, locationInWindow: event.locationInWindow)
    }

    override func mouseDown(with event: NSEvent) {
        var shouldPropagate = true
        if let additionalDelegate = additionalDelegate,
              let (row, column) = rowAndColumnForWindowLocation(event.locationInWindow) {
            shouldPropagate = additionalDelegate.tableView(self, mouseDownFor: row, column: column, locationInWindow: event.locationInWindow, modifiers: event.modifierFlags)
        }
        guard shouldPropagate else { return }
        super.mouseDown(with: event)
    }

    override func mouseEntered(with event: NSEvent) {
        super.mouseEntered(with: event)
        onHoverTableView?(true)
    }

    override func mouseExited(with event: NSEvent) {
        super.mouseExited(with: event)
        guard rowAndColumnForWindowLocation(event.locationInWindow) != nil || self.isMousePoint(event.locationInWindow, in: self.frame)  else {
            onHoverTableView?(false)
            return
        }
    }

    @objc func didDoubleSelectRow() {
        guard let additionalDelegate = additionalDelegate else { return }
        additionalDelegate.tableView(self, didDoubleTap: self.clickedRow)
    }
}
