//
//  TimelineJumpButton.swift
//  Tusker
//
//  Created by Shadowfacts on 2/6/23.
//  Copyright © 2023 Shadowfacts. All rights reserved.
//

import UIKit

class TimelineJumpButton: UIView {
    
    var action: ((Mode) async -> Void)?
    
    override var intrinsicContentSize: CGSize {
        CGSize(width: UIView.noIntrinsicMetric, height: 44)
    }
    
    private let button: UIButton = {
        var config = UIButton.Configuration.plain()
        config.image = UIImage(systemName: "arrow.up")
        config.contentInsets = .zero
        // We don't want a background for this button, even when accessibility button shapes are enabled, because it's in the navbar.
        config.background.backgroundColor = .clear
        return UIButton(configuration: config)
    }()
    
    private(set) var mode = Mode.jump
    var offscreen = false {
        didSet {
            updateOffscreenTransform()
        }
    }
    private(set) var isSyncing = false
    
    init() {
        super.init(frame: .zero)
        
        layer.masksToBounds = true
        
        button.addAction(UIAction(handler: { [unowned self] _ in
            Task {
                switch self.mode {
                case .jump:
                    await self.jumpAction()
                case .sync:
                    await self.syncAction()
                }
            }
        }), for: .touchUpInside)
        
        button.translatesAutoresizingMaskIntoConstraints = false
        addSubview(button)
        NSLayoutConstraint.activate([
            button.leadingAnchor.constraint(equalTo: leadingAnchor),
            button.trailingAnchor.constraint(equalTo: trailingAnchor),
            button.topAnchor.constraint(equalTo: topAnchor),
            button.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
        
        let jumpToPresentAction = UIAction(title: "Jump to Present", image: UIImage(systemName: "arrow.up")) { [unowned self] _ in
            Task {
                self.setMode(.jump, animated: false)
                await self.jumpAction()
            }
        }
        jumpToPresentAction.accessibilityAttributedLabel = TimelinesPageViewController.jumpToPresentTitle
        
        button.menu = UIMenu(children: [
            jumpToPresentAction,
            UIAction(title: "Sync Position", image: UIImage(systemName: "arrow.triangle.2.circlepath"), handler: { [unowned self] _ in
                Task {
                    self.setMode(.sync, animated: false)
                    await self.syncAction()
                }
            })
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        updateOffscreenTransform()
    }
    
    private func updateOffscreenTransform() {
        if offscreen {
            button.transform = CGAffineTransform(translationX: 0, y: button.bounds.height)
        } else {
            button.transform = .identity
        }
    }
    
    func setMode(_ mode: Mode, animated: Bool) {
        guard self.mode != mode else {
            return
        }
        self.mode = mode
        
        var config = UIButton.Configuration.plain()
        config.contentInsets = .zero
        switch mode {
        case .jump:
            config.image = UIImage(systemName: "arrow.up")
        case .sync:
            config.image = UIImage(systemName: "arrow.triangle.2.circlepath")
        }
        
        if animated,
           let snapshot = button.snapshotView(afterScreenUpdates: false) {
            snapshot.translatesAutoresizingMaskIntoConstraints = false
            addSubview(snapshot)
            NSLayoutConstraint.activate([
                snapshot.centerXAnchor.constraint(equalTo: centerXAnchor),
                snapshot.centerYAnchor.constraint(equalTo: centerYAnchor),
            ])
            button.configuration = config
            button.layer.opacity = 0
            UIView.animate(withDuration: 0.5, delay: 0) {
                self.button.layer.opacity = 1
                snapshot.layer.opacity = 0
            } completion: { _ in
                snapshot.removeFromSuperview()
            }
        } else {
            button.configuration = config
        }
    }
    
    private func jumpAction() async {
        button.isUserInteractionEnabled = false
        var config = button.configuration!
        config.showsActivityIndicator = true
        button.configuration = config
        
        await action?(.jump)
        
        config.showsActivityIndicator = false
        button.configuration = config
        button.isUserInteractionEnabled = true
    }
    
    private func syncAction() async {
        isSyncing = true
        button.isUserInteractionEnabled = false
        UIView.animateKeyframes(withDuration: 1, delay: 0, options: .repeat) {
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
                self.button.imageView!.transform = CGAffineTransform(rotationAngle: 0.5 * .pi)
            }
            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
                // the translation is because the symbol isn't perfectly centered
                self.button.imageView!.transform = CGAffineTransform(translationX: -0.5, y: 0).rotated(by: .pi)
            }
        } completion: { _ in
        }

        await action?(.sync)
        
        button.imageView!.layer.removeAllAnimations()
        button.imageView!.transform = .identity
        button.isUserInteractionEnabled = true
        isSyncing = false
        setMode(.jump, animated: true)
    }
    
}

extension TimelineJumpButton {
    enum Mode {
        case jump
        case sync
    }
}
