//
//  ProfileBannerView.swift
//  Mastodon
//
//  Created by MainasuK Cirno on 2021-3-29.
//

import os.log
import UIKit
import ActiveLabel
import TwitterTextEditor
import FLAnimatedImage
import MetaTextView

protocol ProfileHeaderViewDelegate: AnyObject {
    func profileHeaderView(_ profileHeaderView: ProfileHeaderView, avatarImageViewDidPressed imageView: UIImageView)
    func profileHeaderView(_ profileHeaderView: ProfileHeaderView, bannerImageViewDidPressed imageView: UIImageView)
    func profileHeaderView(_ profileHeaderView: ProfileHeaderView, relationshipButtonDidPressed button: ProfileRelationshipActionButton)
    func profileHeaderView(_ profileHeaderView: ProfileHeaderView, activeLabel: ActiveLabel, entityDidPressed entity: ActiveEntity)

    func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, postDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView)
    func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, followingDashboardMeterViewDidPressed followingDashboardMeterView: ProfileStatusDashboardMeterView)
    func profileHeaderView(_ profileHeaderView: ProfileHeaderView, profileStatusDashboardView: ProfileStatusDashboardView, followersDashboardMeterViewDidPressed followersDashboardMeterView: ProfileStatusDashboardMeterView)
}

final class ProfileHeaderView: UIView {
    
    static let avatarImageViewSize = CGSize(width: 56, height: 56)
    static let avatarImageViewCornerRadius: CGFloat = 6
    static let avatarImageViewBorderColor = UIColor.white
    static let avatarImageViewBorderWidth: CGFloat = 2
    static let friendshipActionButtonSize = CGSize(width: 108, height: 34)
    static let bannerImageViewPlaceholderColor = UIColor.systemGray
    
    static let bannerImageViewOverlayViewBackgroundNormalColor = UIColor.black.withAlphaComponent(0.5)
    static let bannerImageViewOverlayViewBackgroundEditingColor = UIColor.black.withAlphaComponent(0.8)
    
    weak var delegate: ProfileHeaderViewDelegate?
    
    var state: State?
    
    let bannerContainerView = UIView()
    let bannerImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.contentMode = .scaleAspectFill
        imageView.image = .placeholder(color: ProfileHeaderView.bannerImageViewPlaceholderColor)
        imageView.backgroundColor = ProfileHeaderView.bannerImageViewPlaceholderColor
        imageView.layer.masksToBounds = true
        imageView.isUserInteractionEnabled = true
        // accessibility
        imageView.accessibilityIgnoresInvertColors = true
        return imageView
    }()

    // known issue:
    // in iOS 14 blur maybe disappear when banner image moving and scaling
    static let bannerImageViewOverlayBlurEffect = UIBlurEffect(style: .systemMaterialDark)
    let bannerImageViewOverlayVisualEffectView: UIVisualEffectView = {
        let overlayView = UIVisualEffectView(effect: nil)
        overlayView.backgroundColor = ProfileHeaderView.bannerImageViewOverlayViewBackgroundNormalColor
        return overlayView
    }()

    let avatarImageViewBackgroundView: UIView = {
        let view = UIView()
        view.layer.masksToBounds = true
        view.layer.cornerRadius = ProfileHeaderView.avatarImageViewCornerRadius
        view.layer.cornerCurve = .continuous
        view.layer.borderColor = ProfileHeaderView.avatarImageViewBorderColor.cgColor
        view.layer.borderWidth = ProfileHeaderView.avatarImageViewBorderWidth
        return view
    }()
    
    let avatarImageView: UIImageView = {
        let imageView = FLAnimatedImageView()
        let placeholderImage = UIImage
            .placeholder(size: ProfileHeaderView.avatarImageViewSize, color: Asset.Colors.Background.systemGroupedBackground.color)
            .af.imageRounded(withCornerRadius: ProfileHeaderView.avatarImageViewCornerRadius, divideRadiusByImageScale: false)
        imageView.image = placeholderImage
        return imageView
    }()

    func setupAvatarOverlayViews() {
        editAvatarBackgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
        editAvatarButton.tintColor = .white
    }

    static let avatarImageViewOverlayBlurEffect = UIBlurEffect(style: .systemUltraThinMaterialDark)
    let avatarImageViewOverlayVisualEffectView: UIVisualEffectView = {
        let visualEffectView = UIVisualEffectView(effect: nil)
        visualEffectView.isUserInteractionEnabled = false
        return visualEffectView
    }()
    
    let editAvatarBackgroundView: UIView = {
        let view = UIView()
        view.backgroundColor = .clear       // set value after view appeared
        view.layer.masksToBounds = true
        view.layer.cornerCurve = .continuous
        view.layer.cornerRadius = ProfileHeaderView.avatarImageViewCornerRadius
        view.alpha = 0 // set initial state invisible
        return view
    }()
    
    let editAvatarButton: HighlightDimmableButton = {
        let button = HighlightDimmableButton()
        button.setImage(UIImage(systemName: "photo", withConfiguration: UIImage.SymbolConfiguration(pointSize: 28)), for: .normal)
        button.tintColor = .clear
        return button
    }()

    let nameTextFieldBackgroundView: UIView = {
        let view = UIView()
        view.layer.masksToBounds = true
        view.layer.cornerCurve = .continuous
        view.layer.cornerRadius = 10
        return view
    }()

    let displayNameStackView = UIStackView()
    let nameMetaText: MetaText = {
        let metaText = MetaText()
        metaText.textView.backgroundColor = .clear
        metaText.textView.isEditable = false
        metaText.textView.isSelectable = false
        metaText.textView.isScrollEnabled = false
        metaText.textView.layer.masksToBounds = false
        metaText.textView.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold), maximumPointSize: 28)
        metaText.textView.textColor = .white
        metaText.textView.textContainer.lineFragmentPadding = 0
        metaText.textAttributes = [
            .font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold), maximumPointSize: 28),
            .foregroundColor: UIColor.white
        ]
        return metaText
    }()
    let nameTextField: UITextField = {
        let textField = UITextField()
        textField.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold), maximumPointSize: 28)
        textField.textColor = .white
        textField.text = "Alice"
        textField.autocorrectionType = .no
        textField.autocapitalizationType = .none
        textField.applyShadow(color: UIColor.black.withAlphaComponent(0.2), alpha: 0.5, x: 0, y: 2, blur: 2, spread: 0)
        return textField
    }()

    let usernameLabel: UILabel = {
        let label = UILabel()
        label.font = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20)
        label.adjustsFontSizeToFitWidth = true
        label.minimumScaleFactor = 0.5
        label.textColor = Asset.Scene.Profile.Banner.usernameGray.color
        label.text = "@alice"
        label.applyShadow(color: UIColor.black.withAlphaComponent(0.2), alpha: 0.5, x: 0, y: 2, blur: 2, spread: 0)
        return label
    }()
    
    let statusDashboardView = ProfileStatusDashboardView()
    let relationshipActionButton: ProfileRelationshipActionButton = {
        let button = ProfileRelationshipActionButton()
        button.titleLabel?.font = .systemFont(ofSize: 17, weight: .semibold)
        return button
    }()
    
    let bioContainerView = UIView()
    let bioContainerStackView = UIStackView()
    let fieldContainerStackView = UIStackView()
    
    let bioActiveLabelContainer: UIView = {
        // use to set margin for active label
        // the display/edit mode bio transition animation should without flicker with that
        let view = UIView()
        // note: comment out to see how it works
        view.layoutMargins = UIEdgeInsets(top: 8, left: 5, bottom: 8, right: 5) // magic from TextEditorView
        return view
    }()
    let bioActiveLabel = ActiveLabel(style: .default)
    let bioTextEditorView: TextEditorView = {
        let textEditorView = TextEditorView()
        textEditorView.scrollView.isScrollEnabled = false
        textEditorView.isScrollEnabled = false
        textEditorView.font = .preferredFont(forTextStyle: .body)
        textEditorView.backgroundColor = Asset.Scene.Profile.Banner.bioEditBackgroundGray.color
        textEditorView.layer.masksToBounds = true
        textEditorView.layer.cornerCurve = .continuous
        textEditorView.layer.cornerRadius = 10
        return textEditorView
    }()
    
    static func createFieldCollectionViewLayout() -> UICollectionViewLayout {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
        let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
        let section = NSCollectionLayoutSection(group: group)
        section.contentInsetsReference = .readableContent
        
        let headerFooterSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(1))
        let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerFooterSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)
        let footer = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerFooterSize, elementKind: UICollectionView.elementKindSectionFooter, alignment: .bottom)
        section.boundarySupplementaryItems = [header, footer]
        // note: toggle this not take effect
        // section.supplementariesFollowContentInsets = false
        
        return UICollectionViewCompositionalLayout(section: section)
    }
    
    let fieldCollectionView: UICollectionView = {
        let collectionViewLayout = ProfileHeaderView.createFieldCollectionViewLayout()
        let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 100, height: 100), collectionViewLayout: collectionViewLayout)
        collectionView.register(ProfileFieldCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ProfileFieldCollectionViewCell.self))
        collectionView.register(ProfileFieldAddEntryCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ProfileFieldAddEntryCollectionViewCell.self))
        collectionView.register(ProfileFieldCollectionViewHeaderFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: ProfileFieldCollectionViewHeaderFooterView.headerReuseIdentifer)
        collectionView.register(ProfileFieldCollectionViewHeaderFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: ProfileFieldCollectionViewHeaderFooterView.footerReuseIdentifer)
        collectionView.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
        collectionView.isScrollEnabled = false
        return collectionView
    }()
    var fieldCollectionViewHeightLaoutConstraint: NSLayoutConstraint!
    var fieldCollectionViewHeightObservation: NSKeyValueObservation?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        _init()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        _init()
    }
    
    deinit {
        fieldCollectionViewHeightObservation = nil
    }
    
}

extension ProfileHeaderView {
    private func _init() {
        backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
        
        // banner
        bannerContainerView.translatesAutoresizingMaskIntoConstraints = false
        bannerContainerView.preservesSuperviewLayoutMargins = true
        addSubview(bannerContainerView)
        NSLayoutConstraint.activate([
            bannerContainerView.topAnchor.constraint(equalTo: topAnchor),
            bannerContainerView.leadingAnchor.constraint(equalTo: leadingAnchor),
            trailingAnchor.constraint(equalTo: bannerContainerView.trailingAnchor),
            readableContentGuide.widthAnchor.constraint(equalTo: bannerContainerView.heightAnchor, multiplier: 3),  // set height to 1/3 of readable frame width
        ])
        
        bannerImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        bannerImageView.frame = bannerContainerView.bounds
        bannerContainerView.addSubview(bannerImageView)
        
        bannerImageViewOverlayVisualEffectView.translatesAutoresizingMaskIntoConstraints = false
        bannerImageView.addSubview(bannerImageViewOverlayVisualEffectView)
        NSLayoutConstraint.activate([
            bannerImageViewOverlayVisualEffectView.topAnchor.constraint(equalTo: bannerImageView.topAnchor),
            bannerImageViewOverlayVisualEffectView.leadingAnchor.constraint(equalTo: bannerImageView.leadingAnchor),
            bannerImageViewOverlayVisualEffectView.trailingAnchor.constraint(equalTo: bannerImageView.trailingAnchor),
            bannerImageViewOverlayVisualEffectView.bottomAnchor.constraint(equalTo: bannerImageView.bottomAnchor),
        ])

        // avatar
        avatarImageViewBackgroundView.translatesAutoresizingMaskIntoConstraints = false
        bannerContainerView.addSubview(avatarImageViewBackgroundView)
        NSLayoutConstraint.activate([
            avatarImageViewBackgroundView.leadingAnchor.constraint(equalTo: bannerContainerView.readableContentGuide.leadingAnchor),
            bannerContainerView.bottomAnchor.constraint(equalTo: avatarImageViewBackgroundView.bottomAnchor, constant: 20),
        ])
        
        avatarImageView.translatesAutoresizingMaskIntoConstraints = false
        avatarImageViewBackgroundView.addSubview(avatarImageView)
        NSLayoutConstraint.activate([
            avatarImageView.topAnchor.constraint(equalTo: avatarImageViewBackgroundView.topAnchor, constant: 0.5 * ProfileHeaderView.avatarImageViewBorderWidth),
            avatarImageView.leadingAnchor.constraint(equalTo: avatarImageViewBackgroundView.leadingAnchor, constant: 0.5 * ProfileHeaderView.avatarImageViewBorderWidth),
            avatarImageViewBackgroundView.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 0.5 * ProfileHeaderView.avatarImageViewBorderWidth),
            avatarImageViewBackgroundView.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor, constant: 0.5 * ProfileHeaderView.avatarImageViewBorderWidth),
            avatarImageView.widthAnchor.constraint(equalToConstant: ProfileHeaderView.avatarImageViewSize.width).priority(.required - 1),
            avatarImageView.heightAnchor.constraint(equalToConstant: ProfileHeaderView.avatarImageViewSize.height).priority(.required - 1),
        ])

        avatarImageViewOverlayVisualEffectView.translatesAutoresizingMaskIntoConstraints = false
        avatarImageViewBackgroundView.addSubview(avatarImageViewOverlayVisualEffectView)
        NSLayoutConstraint.activate([
            avatarImageViewOverlayVisualEffectView.topAnchor.constraint(equalTo: avatarImageViewBackgroundView.topAnchor),
            avatarImageViewOverlayVisualEffectView.leadingAnchor.constraint(equalTo: avatarImageViewBackgroundView.leadingAnchor),
            avatarImageViewOverlayVisualEffectView.trailingAnchor.constraint(equalTo: avatarImageViewBackgroundView.trailingAnchor),
            avatarImageViewOverlayVisualEffectView.bottomAnchor.constraint(equalTo: avatarImageViewBackgroundView.bottomAnchor),
        ])
    
        editAvatarBackgroundView.translatesAutoresizingMaskIntoConstraints = false
        avatarImageView.addSubview(editAvatarBackgroundView)
        NSLayoutConstraint.activate([
            editAvatarBackgroundView.topAnchor.constraint(equalTo: avatarImageView.topAnchor),
            editAvatarBackgroundView.leadingAnchor.constraint(equalTo: avatarImageView.leadingAnchor),
            editAvatarBackgroundView.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor),
            editAvatarBackgroundView.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor),
        ])
        
        editAvatarButton.translatesAutoresizingMaskIntoConstraints = false
        editAvatarBackgroundView.addSubview(editAvatarButton)
        NSLayoutConstraint.activate([
            editAvatarButton.topAnchor.constraint(equalTo: editAvatarBackgroundView.topAnchor),
            editAvatarButton.leadingAnchor.constraint(equalTo: editAvatarBackgroundView.leadingAnchor),
            editAvatarButton.trailingAnchor.constraint(equalTo: editAvatarBackgroundView.trailingAnchor),
            editAvatarButton.bottomAnchor.constraint(equalTo: editAvatarBackgroundView.bottomAnchor),
        ])
        editAvatarBackgroundView.isUserInteractionEnabled = true
        avatarImageView.isUserInteractionEnabled = true

        // name container: [display name container | username]
        let nameContainerStackView = UIStackView()
        nameContainerStackView.preservesSuperviewLayoutMargins = true
        nameContainerStackView.axis = .vertical
        nameContainerStackView.spacing = 7
        nameContainerStackView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(nameContainerStackView)
        NSLayoutConstraint.activate([
            nameContainerStackView.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 12),
            nameContainerStackView.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor),
            nameContainerStackView.centerYAnchor.constraint(equalTo: avatarImageView.centerYAnchor),
        ])
        
        displayNameStackView.axis = .horizontal
        nameTextField.translatesAutoresizingMaskIntoConstraints = false
        displayNameStackView.addArrangedSubview(nameTextField)
        NSLayoutConstraint.activate([
            nameTextField.widthAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
        ])
        nameTextField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        nameTextFieldBackgroundView.translatesAutoresizingMaskIntoConstraints = false
        displayNameStackView.addSubview(nameTextFieldBackgroundView)
        NSLayoutConstraint.activate([
            nameTextField.topAnchor.constraint(equalTo: nameTextFieldBackgroundView.topAnchor, constant: 5),
            nameTextField.leadingAnchor.constraint(equalTo: nameTextFieldBackgroundView.leadingAnchor, constant: 5),
            nameTextFieldBackgroundView.bottomAnchor.constraint(equalTo: nameTextField.bottomAnchor, constant: 5),
            nameTextFieldBackgroundView.trailingAnchor.constraint(equalTo: nameTextField.trailingAnchor, constant: 5),
        ])
        displayNameStackView.bringSubviewToFront(nameTextField)
        displayNameStackView.addArrangedSubview(UIView())

        // overlay meta text for display name
        nameMetaText.textView.translatesAutoresizingMaskIntoConstraints = false
        displayNameStackView.addSubview(nameMetaText.textView)
        NSLayoutConstraint.activate([
            nameMetaText.textView.topAnchor.constraint(equalTo: nameTextField.topAnchor),
            nameMetaText.textView.leadingAnchor.constraint(equalTo: nameTextField.leadingAnchor),
            nameMetaText.textView.trailingAnchor.constraint(equalTo: nameTextField.trailingAnchor),
            nameMetaText.textView.bottomAnchor.constraint(equalTo: nameTextField.bottomAnchor),
        ])
        
        nameContainerStackView.addArrangedSubview(displayNameStackView)
        nameContainerStackView.addArrangedSubview(usernameLabel)
        
        // meta container: [dashboard container | bio container | field container]
        let metaContainerStackView = UIStackView()
        metaContainerStackView.spacing = 16
        metaContainerStackView.axis = .vertical
        metaContainerStackView.preservesSuperviewLayoutMargins = true
        metaContainerStackView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(metaContainerStackView)
        NSLayoutConstraint.activate([
            metaContainerStackView.topAnchor.constraint(equalTo: bannerContainerView.bottomAnchor, constant:  13),
            metaContainerStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
            metaContainerStackView.trailingAnchor.constraint(equalTo: trailingAnchor),
            metaContainerStackView.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
        
        //  dashboard container: [dashboard | friendship action button]
        let dashboardContainerView = UIView()
        dashboardContainerView.preservesSuperviewLayoutMargins = true
        metaContainerStackView.addArrangedSubview(dashboardContainerView)
        
        statusDashboardView.translatesAutoresizingMaskIntoConstraints = false
        dashboardContainerView.addSubview(statusDashboardView)
        NSLayoutConstraint.activate([
            statusDashboardView.topAnchor.constraint(equalTo: dashboardContainerView.topAnchor),
            statusDashboardView.leadingAnchor.constraint(equalTo: dashboardContainerView.readableContentGuide.leadingAnchor),
            statusDashboardView.bottomAnchor.constraint(equalTo: dashboardContainerView.bottomAnchor),
        ])
        
        relationshipActionButton.translatesAutoresizingMaskIntoConstraints = false
        dashboardContainerView.addSubview(relationshipActionButton)
        NSLayoutConstraint.activate([
            relationshipActionButton.topAnchor.constraint(equalTo: dashboardContainerView.topAnchor),
            relationshipActionButton.leadingAnchor.constraint(greaterThanOrEqualTo: statusDashboardView.trailingAnchor, constant: 8),
            relationshipActionButton.trailingAnchor.constraint(equalTo: dashboardContainerView.readableContentGuide.trailingAnchor),
            relationshipActionButton.widthAnchor.constraint(equalToConstant: ProfileHeaderView.friendshipActionButtonSize.width).priority(.defaultHigh),
            relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileHeaderView.friendshipActionButtonSize.height).priority(.defaultHigh),
        ])
        
        bioContainerView.preservesSuperviewLayoutMargins = true
        metaContainerStackView.addArrangedSubview(bioContainerView)
        
        bioContainerStackView.translatesAutoresizingMaskIntoConstraints = false
        bioContainerView.addSubview(bioContainerStackView)
        NSLayoutConstraint.activate([
            bioContainerStackView.topAnchor.constraint(equalTo: bioContainerView.topAnchor),
            bioContainerStackView.leadingAnchor.constraint(equalTo: bioContainerView.readableContentGuide.leadingAnchor),
            bioContainerStackView.trailingAnchor.constraint(equalTo: bioContainerView.readableContentGuide.trailingAnchor),
            bioContainerStackView.bottomAnchor.constraint(equalTo: bioContainerView.bottomAnchor),
        ])
        
        bioActiveLabel.translatesAutoresizingMaskIntoConstraints = false
        bioActiveLabelContainer.addSubview(bioActiveLabel)
        NSLayoutConstraint.activate([
            bioActiveLabel.topAnchor.constraint(equalTo: bioActiveLabelContainer.layoutMarginsGuide.topAnchor),
            bioActiveLabel.leadingAnchor.constraint(equalTo: bioActiveLabelContainer.layoutMarginsGuide.leadingAnchor),
            bioActiveLabel.trailingAnchor.constraint(equalTo: bioActiveLabelContainer.layoutMarginsGuide.trailingAnchor),
            bioActiveLabel.bottomAnchor.constraint(equalTo: bioActiveLabelContainer.layoutMarginsGuide.bottomAnchor),
        ])
        
        bioContainerStackView.axis = .vertical
        bioContainerStackView.addArrangedSubview(bioActiveLabelContainer)
        bioContainerStackView.addArrangedSubview(bioTextEditorView)
        
        fieldCollectionView.translatesAutoresizingMaskIntoConstraints = false
        metaContainerStackView.addArrangedSubview(fieldCollectionView)
        fieldCollectionViewHeightLaoutConstraint = fieldCollectionView.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh)
        NSLayoutConstraint.activate([
            fieldCollectionViewHeightLaoutConstraint,
        ])
        fieldCollectionViewHeightObservation = fieldCollectionView.observe(\.contentSize, options: .new, changeHandler: { [weak self] tableView, _ in
            guard let self = self else { return }
            guard self.fieldCollectionView.contentSize.height != .zero else {
                self.fieldCollectionViewHeightLaoutConstraint.constant = 44
                return
            }
            self.fieldCollectionViewHeightLaoutConstraint.constant = self.fieldCollectionView.contentSize.height
        })
        
        bringSubviewToFront(bannerContainerView)
        bringSubviewToFront(nameContainerStackView)
        
        bioActiveLabel.delegate = self
        
        let avatarImageViewSingleTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
        avatarImageView.addGestureRecognizer(avatarImageViewSingleTapGestureRecognizer)
        avatarImageViewSingleTapGestureRecognizer.addTarget(self, action: #selector(ProfileHeaderView.avatarImageViewDidPressed(_:)))
        
        let bannerImageViewSingleTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
        bannerImageView.addGestureRecognizer(bannerImageViewSingleTapGestureRecognizer)
        bannerImageViewSingleTapGestureRecognizer.addTarget(self, action: #selector(ProfileHeaderView.bannerImageViewDidPressed(_:)))
        
        relationshipActionButton.addTarget(self, action: #selector(ProfileHeaderView.relationshipActionButtonDidPressed(_:)), for: .touchUpInside)
        
        configure(state: .normal)
    }

}

extension ProfileHeaderView {
    enum State {
        case normal
        case editing
    }
    
    func configure(state: State) {
        guard self.state != state else { return }   // avoid redundant animation
        self.state = state
        
        let animator = UIViewPropertyAnimator(duration: 0.33, curve: .easeInOut)
        
        switch state {
        case .normal:
            nameMetaText.textView.alpha = 1
            nameTextField.alpha = 0
            nameTextField.isEnabled = false
            bioActiveLabelContainer.isHidden = false
            bioTextEditorView.isHidden = true
            
            animator.addAnimations {
                self.bannerImageViewOverlayVisualEffectView.backgroundColor = ProfileHeaderView.bannerImageViewOverlayViewBackgroundNormalColor
                self.nameTextFieldBackgroundView.backgroundColor = .clear
                self.editAvatarBackgroundView.alpha = 0
            }
            animator.addCompletion { _ in
                self.editAvatarBackgroundView.isHidden = true
            }
        case .editing:
            nameMetaText.textView.alpha = 0
            nameTextField.isEnabled = true
            nameTextField.alpha = 1
            bioActiveLabelContainer.isHidden = true
            bioTextEditorView.isHidden = false
            
            editAvatarBackgroundView.isHidden = false
            editAvatarBackgroundView.alpha = 0
            bioTextEditorView.backgroundColor = .clear
            animator.addAnimations {
                self.bannerImageViewOverlayVisualEffectView.backgroundColor = ProfileHeaderView.bannerImageViewOverlayViewBackgroundEditingColor
                self.nameTextFieldBackgroundView.backgroundColor = Asset.Scene.Profile.Banner.nameEditBackgroundGray.color
                self.editAvatarBackgroundView.alpha = 1
                self.bioTextEditorView.backgroundColor = Asset.Scene.Profile.Banner.bioEditBackgroundGray.color
            }
        }
        
        animator.startAnimation()
    }
}

extension ProfileHeaderView {
    @objc private func relationshipActionButtonDidPressed(_ sender: UIButton) {
        os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
        assert(sender === relationshipActionButton)
        delegate?.profileHeaderView(self, relationshipButtonDidPressed: relationshipActionButton)
    }
    
    @objc private func avatarImageViewDidPressed(_ sender: UITapGestureRecognizer) {
        os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
        delegate?.profileHeaderView(self, avatarImageViewDidPressed: avatarImageView)
    }
    
    @objc private func bannerImageViewDidPressed(_ sender: UITapGestureRecognizer) {
        os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
        delegate?.profileHeaderView(self, bannerImageViewDidPressed: bannerImageView)
    }
}

// MARK: - ActiveLabelDelegate
extension ProfileHeaderView: ActiveLabelDelegate {
    func activeLabel(_ activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
        os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select entity: %s", ((#file as NSString).lastPathComponent), #line, #function, entity.primaryText)
        delegate?.profileHeaderView(self, activeLabel: activeLabel, entityDidPressed: entity)
    }
}

// MARK: - ProfileStatusDashboardViewDelegate
extension ProfileHeaderView: ProfileStatusDashboardViewDelegate {
    
    func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, postDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) {
        delegate?.profileHeaderView(self, profileStatusDashboardView: dashboardView, postDashboardMeterViewDidPressed: dashboardMeterView)
    }
    
    func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, followingDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) {
        delegate?.profileHeaderView(self, profileStatusDashboardView: dashboardView, followingDashboardMeterViewDidPressed: dashboardMeterView)
    }
    
    func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, followersDashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView) {
        delegate?.profileHeaderView(self, profileStatusDashboardView: dashboardView, followersDashboardMeterViewDidPressed: dashboardMeterView)
    }
 
}

// MARK: - AvatarConfigurableView
extension ProfileHeaderView: AvatarConfigurableView {
    static var configurableAvatarImageSize: CGSize { avatarImageViewSize }
    static var configurableAvatarImageCornerRadius: CGFloat { avatarImageViewCornerRadius }
    var configurableAvatarImageView: UIImageView? { return avatarImageView }
    var configurableAvatarButton: UIButton? { return nil }
}


#if DEBUG
import SwiftUI

struct ProfileHeaderView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            UIViewPreview(width: 375) {
                let banner = ProfileHeaderView()
                banner.bannerImageView.image = UIImage(named: "lucas-ludwig")
                return banner
            }
            .previewLayout(.fixed(width: 375, height: 800))
            UIViewPreview(width: 375) {
                let banner = ProfileHeaderView()
                //banner.bannerImageView.image = UIImage(named: "peter-luo")
                return banner
            }
            .preferredColorScheme(.dark)
            .previewLayout(.fixed(width: 375, height: 800))
        }
    }
}
#endif
