//
//  StatusMetaIndicatorsView.swift
//  Tusker
//
//  Created by Shadowfacts on 1/22/22.
//  Copyright © 2022 Shadowfacts. All rights reserved.
//

import UIKit
import Pachyderm

class StatusMetaIndicatorsView: UIView {
    
    var allowedIndicators: Indicator = .all
    var squeezeHorizontal = false
    // The axis in which the indicators grow
    var primaryAxis: NSLayoutConstraint.Axis = .vertical
    // Only used when using single axis mode
    var secondaryAxisAlignment: Alignment = .leading
    private var images: [UIImageView] = []
    private var isUsingSingleAxis = false
    private var statusID: String?
    
    private var needsSingleAxis: Bool {
        traitCollection.preferredContentSizeCategory > .extraLarge
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() {
        NotificationCenter.default.addObserver(self, selector: #selector(configureImageViews), name: UIAccessibility.boldTextStatusDidChangeNotification, object: nil)
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        if isUsingSingleAxis != needsSingleAxis {
            for image in images {
                configureImageView(image)
            }
            placeImageViews(images)
        }
    }
    
    @objc private func configureImageViews() {
        for image in images {
            configureImageView(image)
        }
    }
    
    private func configureImageView(_ imageView: UIImageView) {
        let weight: UIImage.SymbolWeight = UIAccessibility.isBoldTextEnabled ? .regular : traitCollection.preferredContentSizeCategory > .large ? .light : .thin
        let scale: UIImage.SymbolScale = traitCollection.preferredContentSizeCategory > .extraLarge ? .large : .default
        imageView.preferredSymbolConfiguration = .init(pointSize: 0, weight: weight, scale: scale)
    }
    
    func updateUI(status: StatusMO) {
        guard statusID != status.id else {
            return
        }
        statusID = status.id
        
        var images: [UIImage] = []
        
        if allowedIndicators.contains(.reply) && Preferences.shared.showIsStatusReplyIcon && status.inReplyToID != nil {
            images.append(UIImage(systemName: "bubble.left.and.bubble.right")!)
        }
        
        if allowedIndicators.contains(.visibility) && Preferences.shared.alwaysShowStatusVisibilityIcon {
            images.append(UIImage(systemName: status.visibility.unfilledImageName)!)
        }
        
        if allowedIndicators.contains(.localOnly) && status.localOnly {
            images.append(UIImage(named: "link.broken")!)
        }
        
        let views = images.map {
            let v = UIImageView(image: $0)
            v.translatesAutoresizingMaskIntoConstraints = false
            v.contentMode = .scaleAspectFit
            v.tintColor = .secondaryLabel
            configureImageView(v)
            return v
        }
        placeImageViews(views)
    }
    
    private func placeImageViews(_ imageViews: [UIImageView]) {
        images.forEach { $0.removeFromSuperview() }
        images = imageViews
        
        guard !images.isEmpty else {
            return
        }
        
        isUsingSingleAxis = needsSingleAxis
        
        if needsSingleAxis {
            for v in images {
                addSubview(v)
                
                switch (primaryAxis, secondaryAxisAlignment) {
                case (.horizontal, .leading):
                    v.topAnchor.constraint(equalTo: topAnchor).isActive = true
                case (.horizontal, .trailing):
                    v.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
                case (.vertical, .leading):
                    v.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
                case (.vertical, .trailing):
                    v.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
                case (_, _):
                    fatalError()
                }
            }
            if primaryAxis == .vertical {
                images.first!.topAnchor.constraint(equalTo: topAnchor).isActive = true
                images.last!.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
            } else {
                images.first!.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
                images.last!.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
            }
            for (a, b) in zip(images, images.dropFirst()) {
                if primaryAxis == .vertical {
                    b.topAnchor.constraint(equalTo: a.bottomAnchor, constant: 4).isActive = true
                } else {
                    b.leadingAnchor.constraint(equalTo: a.trailingAnchor, constant: 4).isActive = true
                }
            }
            return
        }
        
        guard primaryAxis == .vertical || imageViews.count <= 2 else {
            fatalError("StatusMetaIndicatorsView does not support horizontal primary axis with more than 2 views yet")
        }
        
        for (index, v) in images.enumerated() {
            addSubview(v)
            
            if index % 2 == 0 {
                if index == images.count - 1 {
                    v.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
                    v.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor).isActive = true
                } else {
                    v.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
                }
            } else {
                if squeezeHorizontal {
                    v.leadingAnchor.constraint(equalTo: self.images[index - 1].trailingAnchor, constant: 4).isActive = true
                } else {
                    v.leadingAnchor.constraint(greaterThanOrEqualTo: self.images[index - 1].trailingAnchor, constant: 4).isActive = true
                }
                v.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
            }
            
            let row = index / 2
            if row == 0 {
                v.topAnchor.constraint(equalTo: topAnchor).isActive = true
            } else {
                v.topAnchor.constraint(equalTo: self.images[index - 1].bottomAnchor, constant: 4).isActive = true
            }
            v.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor).isActive = true
        }
    }
    
    struct Indicator: OptionSet {
        let rawValue: Int
        
        static let reply = Indicator(rawValue: 1 << 0)
        static let visibility = Indicator(rawValue: 1 << 1)
        static let localOnly = Indicator(rawValue: 1 << 2)
        
        static let all: Indicator = [.reply, .visibility, .localOnly]
    }
    
    enum Alignment {
        case leading, trailing
    }
}
