//
//  LNPopupView.swift
//  Lanu
//
//  Created by OneeChan on 2025/11/14.
//

import Foundation
import UIKit
import SnapKit

enum LNPopupViewHeight {
    case auto
    case percent(CGFloat)
    case height(CGFloat)
}

class LNPopupView: UIView {
    let backgroundView = UIView()
    let container = UIView()
    var containerHeight: LNPopupViewHeight = .auto {
        didSet {
            container.snp.makeConstraints { make in
                switch containerHeight {
                case .percent(let percent):
                    make.height.equalToSuperview().multipliedBy(percent)
                case .height(let height):
                    make.height.equalTo(height)
                case .auto: break
                }
            }
        }
    }
    var touchOutsideToCancel = true
    var ignoreKeyboardToDismiss = false
    var onTouchOutside: (() -> Void)?
    private var bottomConstraint: Constraint?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupViews()
    }
    
    func popup(_ targetView: UIView? = nil, animated: Bool = true) {
        let parentView: UIView? = if let window = targetView as? UIWindow {
            window
        } else if let view = targetView?.viewController?.view {
            view
        } else if let window = UIView.appKeyWindow {
            window
        } else {
            nil
        }
        guard let parentView else { return }
        
        frame = parentView.bounds
        parentView.addSubview(self)
        snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        layoutIfNeeded()
        
        moveToShowupPosition()
        window?.endEditing(true)
        if animated {
            backgroundView.backgroundColor = .clear
            UIView.animate(withDuration: 0.25) {
                self.backgroundView.backgroundColor = .black.withAlphaComponent(0.4)
                self.layoutIfNeeded()
            }
        } else {
            backgroundView.backgroundColor = .black.withAlphaComponent(0.4)
            layoutIfNeeded()
        }
    }
    
    func dismiss(animated: Bool = true) {
        endEditing(true)
        moveToHiddenPosition()
        if animated {
            UIView.animate(withDuration: 0.25) {
                self.backgroundView.backgroundColor = .clear
                self.layoutIfNeeded()
            } completion: { [weak self] _ in
                guard let self else { return }
                self.removeFromSuperview()
            }
        } else {
            removeFromSuperview()
        }
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension LNPopupView {
    private func setupViews() {
        backgroundView.onTap { [weak self] in
            guard let self else { return }
            if !ignoreKeyboardToDismiss,
               LNKeyboardManager.shared.isEditing {
                endEditing(true)
            } else if touchOutsideToCancel {
                if let onTouchOutside {
                    onTouchOutside()
                } else {
                    dismiss()
                }
            } else {
                endEditing(true)
            }
        }
        insertSubview(backgroundView, at: 0)
        backgroundView.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.bottom.equalToSuperview()
            make.top.equalToSuperview().offset(-(UIView.navigationBarHeight + UIView.statusBarHeight))
        }
        
        container.backgroundColor = .white
        container.layer.cornerRadius = 20
        container.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
        addSubview(container)
        container.snp.makeConstraints { make in
            make.horizontalEdges.equalToSuperview()
            make.top.equalTo(snp.bottom).priority(.medium)
            bottomConstraint = make.bottom.equalToSuperview().priority(.low).constraint
        }
        
        let dismissView = UIView()
        container.addSubview(dismissView)
        dismissView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        dismissView.onTap { [weak self] in
            guard let self else { return }
            endEditing(true)
        }
        
        LNEventDeliver.addObserver(self)
    }
    
    private func moveToHiddenPosition() {
        bottomConstraint?.update(priority: .low).update(offset: 0)
    }
    
    private func moveToShowupPosition() {
        bottomConstraint?.update(priority: .high).update(offset: 0)
    }
    
    private func onKeyboardShowup(_ keyboardHeight: CGFloat) {
        bottomConstraint?.update(offset: -keyboardHeight)
    }
}

extension LNPopupView: LNKeyboardNotify {
    func onKeyboardWillShow(curInput: UIView?, keyboardHeight: CGFloat) {
        guard let curInput, curInput.isDescendant(of: self) == true else { return }
        let containerY = bounds.height - container.bounds.height
        let editViewY = curInput.convert(curInput.bounds, to: container).maxY
        
        let offset = bounds.height - (containerY + editViewY) - keyboardHeight - 16
        
        if offset < 0 {
            onKeyboardShowup(-offset)
        }
    }
    
    func onKeyboardShow(curInput: UIView?, keyboardHeight: CGFloat) {
        guard curInput?.isDescendant(of: self) == true else { return }
        layoutIfNeeded()
    }
    
    func onKeyboardWillHide(curInput: UIView?) {
        guard curInput?.isDescendant(of: self) == true else { return }
        moveToShowupPosition()
    }
    
    func onKeyboardHide(curInput: UIView?) {
        guard curInput?.isDescendant(of: self) == true else { return }
        layoutIfNeeded()
    }
}
