import UIKit
import Shared
import SnapKit
import Combine

final class ScanDisplayShareView: UIView {
    enum Action {
        case info
        case addEmail
        case addPhone
        case toggleEmail
        case togglePhone
    }

    private var isExpanded = false {
        didSet { updateBottomConstraint() }
    }

    private let upperView = UIView()
    private let lowerView = UIView()
    private var bottomConstraint: Constraint?

    private let imageView = UIImageView()
    private let titleView = TextWithInfoView()
    private let emailView = AttributeSwitcher()
    private let phoneView = AttributeSwitcher()
    private var cancellables = Set<AnyCancellable>()

    private var currentConstraintConstant: CGFloat = 0.0 {
        didSet { bottomConstraint?.update(offset: currentConstraintConstant) }
    }

    private var bottomConstraintExpanded: CGFloat {
        -lowerView.frame.height
    }

    private var bottomConstraintNotExpanded: CGFloat {
        0
    }

    var actionPublisher: AnyPublisher<Action, Never> {
        actionSubject.eraseToAnyPublisher()
    }

    private let actionSubject = PassthroughSubject<Action, Never>()

    init() {
        super.init(frame: .zero)

        upperView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(didPan(_:))))
        lowerView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(didPan(_:))))

        layer.cornerRadius = 30
        imageView.image = Asset.scanDropdown.image
        backgroundColor = Asset.neutralWhite.color
        clipsToBounds = true
        layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]

        addSubview(upperView)
        addSubview(lowerView)

        upperView.addSubview(imageView)
        upperView.addSubview(titleView)
        lowerView.addSubview(emailView)
        lowerView.addSubview(phoneView)

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineBreakMode = .byWordWrapping

        titleView.setup(
            text: Localized.Scan.Display.Share.title,
            attributes: [
                .foregroundColor: Asset.neutralBody.color,
                .font: Fonts.Mulish.regular.font(size: 16.0) as Any,
                .paragraphStyle: paragraphStyle
            ],
            didTapInfo: { [weak self] in self?.actionSubject.send(.info) }
        )

        emailView.switcherView
            .publisher(for: .valueChanged)
            .sink { [unowned self] in actionSubject.send(.toggleEmail) }
            .store(in: &cancellables)

        phoneView.switcherView
            .publisher(for: .valueChanged)
            .sink { [unowned self] in actionSubject.send(.togglePhone) }
            .store(in: &cancellables)

        emailView.addButton
            .publisher(for: .touchUpInside)
            .sink { [unowned self] in actionSubject.send(.addEmail) }
            .store(in: &cancellables)

        phoneView.addButton
            .publisher(for: .touchUpInside)
            .sink { [unowned self] in actionSubject.send(.addPhone) }
            .store(in: &cancellables)

        emailView.setup(state: nil, title: Localized.Scan.Display.Share.email)
        phoneView.setup(state: nil, title: Localized.Scan.Display.Share.phone)
        emailView.alpha = 0.0
        phoneView.alpha = 0.0

        imageView.snp.makeConstraints {
            $0.top.equalToSuperview().offset(15)
            $0.centerX.equalToSuperview()
        }

        titleView.snp.makeConstraints {
            $0.top.equalTo(imageView.snp.bottom).offset(10)
            $0.left.equalToSuperview().offset(40)
            $0.right.lessThanOrEqualToSuperview().offset(-40)
            $0.centerY.equalToSuperview()
        }

        emailView.snp.makeConstraints {
            $0.top.equalToSuperview()
            $0.left.equalToSuperview().offset(40)
            $0.right.equalToSuperview().offset(-40)
        }

        phoneView.snp.makeConstraints {
            $0.top.equalTo(emailView.snp.bottom).offset(25)
            $0.left.equalToSuperview().offset(40)
            $0.right.equalToSuperview().offset(-40)
            $0.bottom.equalToSuperview().offset(-40)
        }

        upperView.snp.makeConstraints {
            $0.top.equalToSuperview()
            $0.left.equalToSuperview()
            $0.right.equalToSuperview()
            bottomConstraint = $0.bottom
                .equalTo(safeAreaLayoutGuide)
                .constraint
        }

        lowerView.snp.makeConstraints {
            $0.top.equalTo(upperView.snp.bottom).offset(-30)
            $0.left.equalToSuperview()
            $0.right.equalToSuperview()
        }
    }

    required init?(coder: NSCoder) { nil }

    func setup(email state: AttributeSwitcher.State?) {
        emailView.setup(state: state, title: Localized.Scan.Display.Share.email)
    }

    func setup(phone state: AttributeSwitcher.State?) {
        phoneView.setup(state: state, title: Localized.Scan.Display.Share.phone)
    }

    @objc private func didPan(_ sender: UIPanGestureRecognizer) {
        switch sender.state {
        case .began, .changed:
            let isUpwards = sender.translation(in: self).y < 0
            let result = currentConstraintConstant + sender.translation(in: self).y

            if isUpwards {
                currentConstraintConstant = max(bottomConstraintExpanded, result)
            } else {
                currentConstraintConstant = min(bottomConstraintNotExpanded, result)
            }

            let currentMinusExpanded = currentConstraintConstant - bottomConstraintExpanded
            let notExpandedMinusExpanded = bottomConstraintNotExpanded - bottomConstraintExpanded
            let alpha = 1 - (currentMinusExpanded / abs(notExpandedMinusExpanded))
            emailView.alpha = alpha
            phoneView.alpha = alpha

        case .cancelled, .ended, .failed:
            let currentMinusExpanded = currentConstraintConstant - bottomConstraintExpanded
            let notExpandedMinusExpanded = bottomConstraintNotExpanded - bottomConstraintExpanded
            let percentage = currentMinusExpanded / abs(notExpandedMinusExpanded)
            isExpanded = percentage < 0.5

        case .possible:
            break
        @unknown default:
            break
        }
    }

    private func updateBottomConstraint() {
        if isExpanded {
            emailView.alpha = 1.0
            phoneView.alpha = 1.0
            currentConstraintConstant = bottomConstraintExpanded
        } else {
            emailView.alpha = 0.0
            phoneView.alpha = 0.0
            currentConstraintConstant = bottomConstraintNotExpanded
        }
    }
}