//
//  TimelineGapCollectionViewCell.swift
//  Tusker
//
//  Created by Shadowfacts on 11/16/22.
//  Copyright © 2022 Shadowfacts. All rights reserved.
//

import UIKit

class TimelineGapCollectionViewCell: UICollectionViewCell {
    
    private(set) var direction = TimelineGapDirection.above
    
    private let indicator = UIActivityIndicatorView(style: .medium)
    private let chevronView = AnimatingChevronView()
    private let fillView = UIView()
    
    var fillGap: ((TimelineGapDirection) async -> Void)?
    
    override var isHighlighted: Bool {
        didSet {
            backgroundColor = isHighlighted ? .appFill : .appSecondaryBackground
        }
    }
    
    var showsIndicator: Bool = false {
        didSet {
            if showsIndicator {
                indicator.isHidden = false
                indicator.startAnimating()
            } else {
                indicator.isHidden = true
                indicator.stopAnimating()
            }
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        backgroundColor = .appSecondaryBackground
        
        fillView.backgroundColor = .tintColor
        fillView.alpha = 0.75
        fillView.layer.masksToBounds = true
        fillView.layer.cornerRadius = 8
        fillView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(fillView)
        
        let label = UILabel()
        label.text = "Load more"
        label.font = .preferredFont(forTextStyle: .headline)
        label.adjustsFontForContentSizeCategory = true
        label.textColor = .white
        
        chevronView.tintColor = .white
        chevronView.update(direction: .above)
        
        let stack = UIStackView(arrangedSubviews: [
            label,
            chevronView,
        ])
        stack.axis = .horizontal
        stack.spacing = 8
        stack.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(stack)
        
        indicator.isHidden = true
        indicator.color = .tintColor
        indicator.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(indicator)
        
        NSLayoutConstraint.activate([
            stack.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
            stack.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
            
            fillView.leadingAnchor.constraint(equalTo: stack.leadingAnchor, constant: -8),
            // optical centering, babey
            fillView.trailingAnchor.constraint(equalTo: stack.trailingAnchor, constant: 10),
            fillView.topAnchor.constraint(equalTo: stack.topAnchor, constant: -4),
            fillView.bottomAnchor.constraint(equalTo: stack.bottomAnchor, constant: 4),
            
            indicator.trailingAnchor.constraint(equalTo: stack.leadingAnchor, constant: -12),
            indicator.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
            
            contentView.heightAnchor.constraint(equalToConstant: 52),
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        update()
    }
    
    func update() {
        guard let superview = superview as? UICollectionView else {
            return
        }
        let yInParent = frame.minY - superview.contentOffset.y
        let centerInParent = yInParent + bounds.height / 2
        let centerOfParent = superview.frame.height / 2
        
        let newDirection: TimelineGapDirection
        if centerInParent > centerOfParent {
            newDirection = .above
        } else {
            newDirection = .below
        }
        
        if newDirection != direction {
            direction = newDirection
            chevronView.update(direction: newDirection)
        }
    }
    
    // MARK: Accessibility
    
    override var isAccessibilityElement: Bool {
        get { true }
        set {}
    }
    
    override var accessibilityLabel: String? {
        get {
            "Load \(direction.accessibilityLabel)"
        }
        set {}
    }
    
    override var accessibilityCustomActions: [UIAccessibilityCustomAction]? {
        get {
            [TimelineGapDirection.below, .above].map { dir in
                UIAccessibilityCustomAction(name: "Load \(dir.accessibilityLabel)") { [weak self] _ in
                    guard let self else { return false }
                    Task {
                        self.showsIndicator = true
                        await self.fillGap?(dir)
                        self.showsIndicator = false
                    }
                    return true
                }
            }
        }
        set {}
    }
    
}

private class AnimatingChevronView: UIView {
    
    override class var layerClass: AnyClass { CAShapeLayer.self }
    var shapeLayer: CAShapeLayer { layer as! CAShapeLayer }
    
    override var intrinsicContentSize: CGSize { CGSize(width: 20, height: 25) }
    
    var animator: UIViewPropertyAnimator?
    
    let upPath: CGPath = {
        let path = UIBezierPath()
        let width: CGFloat = 20
        let height: CGFloat = 25
        path.move(to: CGPoint(x: 0, y: height / 2))
        path.addLine(to: CGPoint(x: width / 2, y: height / 5))
        path.addLine(to: CGPoint(x: width, y: height / 2))
        return path.cgPath
    }()
    let downPath: CGPath = {
        let path = UIBezierPath()
        let width: CGFloat = 20
        let height: CGFloat = 25
        path.move(to: CGPoint(x: 0, y: height / 2))
        path.addLine(to: CGPoint(x: width / 2, y: 4 * height / 5))
        path.addLine(to: CGPoint(x: width, y: height / 2))
        return path.cgPath
    }()
    
    init() {
        super.init(frame: .zero)
        shapeLayer.fillColor = nil
        shapeLayer.strokeColor = tintColor.cgColor
        shapeLayer.lineCap = .round
        shapeLayer.lineJoin = .round
        shapeLayer.lineWidth = 3
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func tintColorDidChange() {
        super.tintColorDidChange()
        shapeLayer.strokeColor = tintColor.cgColor
    }
    
    func update(direction: TimelineGapDirection) {
        if animator?.isRunning == true {
            animator!.stopAnimation(true)
        }
        animator = UIViewPropertyAnimator(duration: 0.1, curve: .linear) {
            if direction == .below {
                self.shapeLayer.path = self.upPath
            } else {
                self.shapeLayer.path = self.downPath
            }
        }
        animator!.startAnimation()
    }
    
}
