//
//  StatusEditCollectionViewCell.swift
//  Tusker
//
//  Created by Shadowfacts on 5/11/23.
//  Copyright © 2023 Shadowfacts. All rights reserved.
//

import UIKit
import Pachyderm

@MainActor
protocol StatusEditCollectionViewCellDelegate: AnyObject, TuskerNavigationDelegate {
    func statusEditCellNeedsReconfigure(_ cell: StatusEditCollectionViewCell, animated: Bool, completion: (() -> Void)?)
}

class StatusEditCollectionViewCell: UICollectionViewListCell {
    
    private lazy var contentVStack = UIStackView(arrangedSubviews: [
        timestampLabel,
        contentWarningLabel,
        collapseButton,
        contentContainer,
    ]).configure {
        $0.axis = .vertical
        $0.spacing = 4
        $0.alignment = .fill
    }
    
    private lazy var timestampLabel = UILabel().configure {
        $0.textColor = .secondaryLabel
        $0.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
            .traits: [
                UIFontDescriptor.TraitKey.weight: UIFont.Weight.light.rawValue,
            ]
        ]), size: 0)
        $0.adjustsFontForContentSizeCategory = true
    }
    
    private lazy var contentWarningLabel = EmojiLabel().configure {
        $0.numberOfLines = 0
        $0.textColor = .secondaryLabel
        $0.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).addingAttributes([
            .traits: [
                UIFontDescriptor.TraitKey.weight: UIFont.Weight.bold.rawValue
            ]
        ]), size: 0)
        $0.adjustsFontForContentSizeCategory = true
        $0.setContentHuggingPriority(.defaultHigh, for: .vertical)
        $0.isUserInteractionEnabled = true
        $0.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(collapseButtonPressed)))
    }
    
    private lazy var collapseButton = StatusCollapseButton(configuration: {
        var config = UIButton.Configuration.filled()
        config.image = UIImage(systemName: "chevron.down")
        return config
    }()).configure {
        $0.tintAdjustmentMode = .normal
        $0.setContentHuggingPriority(.defaultHigh, for: .vertical)
        $0.addTarget(self, action: #selector(collapseButtonPressed), for: .touchUpInside)
    }
    
    private let contentContainer = StatusContentContainer<StatusEditContentTextView, StatusEditPollView>(useTopSpacer: false).configure {
        $0.contentTextView.defaultFont = TimelineStatusCollectionViewCell.contentFont
        $0.contentTextView.monospaceFont = TimelineStatusCollectionViewCell.monospaceFont
        $0.contentTextView.paragraphStyle = TimelineStatusCollectionViewCell.contentParagraphStyle
        $0.setContentHuggingPriority(.defaultLow, for: .vertical)
    }
    
    weak var delegate: StatusEditCollectionViewCellDelegate?
    private var mastodonController: MastodonController! { delegate?.apiController }
    
    private var edit: StatusEdit!
    private var statusState: CollapseState!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        contentVStack.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(contentVStack)
        NSLayoutConstraint.activate([
            contentVStack.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
            contentVStack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -6),
            contentVStack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
            contentVStack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: Accessibility
    
    override var isAccessibilityElement: Bool {
        get { true }
        set {}
    }
    
    override var accessibilityAttributedLabel: NSAttributedString? {
        get {
            var str: AttributedString = ""
            if statusState.collapsed ?? false {
                if !edit.spoilerText.isEmpty {
                    str += AttributedString(edit.spoilerText)
                    str += ", "
                }
                str += "collapsed"
            } else {
                str += AttributedString(contentContainer.contentTextView.attributedText)
                
                if edit.attachments.count > 0 {
                    let includeDescriptions: Bool
                    switch Preferences.shared.attachmentBlurMode {
                    case .useStatusSetting:
                        includeDescriptions = !Preferences.shared.blurMediaBehindContentWarning || edit.spoilerText.isEmpty
                    case .always:
                        includeDescriptions = true
                    case .never:
                        includeDescriptions = false
                    }
                    if includeDescriptions {
                        if edit.attachments.count == 1 {
                            let attachment = edit.attachments[0]
                            let desc = attachment.description?.isEmpty == false ? attachment.description! : "no description"
                            str += AttributedString(", attachment: \(desc)")
                        } else {
                            for (index, attachment) in edit.attachments.enumerated() {
                                let desc = attachment.description?.isEmpty == false ? attachment.description! : "no description"
                                str += AttributedString(", attachment \(index + 1): \(desc)")
                            }
                        }
                    } else {
                        str += AttributedString(", \(edit.attachments.count) attachment\(edit.attachments.count == 1 ? "" : "s")")
                    }
                }
                if edit.poll != nil {
                    str += ", poll"
                }
            }
            return NSAttributedString(str)
        }
        set {}
    }
    
    override var accessibilityHint: String? {
        get {
            if statusState.collapsed ?? false {
                return "Double tap to expand the post."
            } else {
                return nil
            }
        }
        set {}
    }
    
    override func accessibilityActivate() -> Bool {
        if statusState.collapsed ?? false {
            collapseButtonPressed()
        }
        return true
    }
    
    // MARK: Configure UI
    
    func updateUI(edit: StatusEdit, state: CollapseState, index: Int) {
        self.edit = edit
        self.statusState = state
        
        timestampLabel.text = ConversationMainStatusCollectionViewCell.dateFormatter.string(from: edit.createdAt)
        
        contentContainer.contentTextView.setTextFrom(edit: edit, index: index)
        contentContainer.contentTextView.navigationDelegate = delegate
        contentContainer.attachmentsView.delegate = self
        contentContainer.attachmentsView.updateUI(attachments: edit.attachments)
        contentContainer.pollView.isHidden = edit.poll == nil
        contentContainer.pollView.updateUI(poll: edit.poll, emojis: edit.emojis)
        contentContainer.cardView.isHidden = true
        
        contentWarningLabel.text = edit.spoilerText
        contentWarningLabel.isHidden = edit.spoilerText.isEmpty
        if !contentWarningLabel.isHidden {
            contentWarningLabel.setEmojis(edit.emojis, identifier: index)
        }
        
        _ = state.resolveFor(status: edit, height: {
            let width = self.bounds.width - 2*16
            return contentContainer.estimateVisibleSubviewHeight(effectiveWidth: width)
        })
        collapseButton.isHidden = !state.collapsible!
        contentContainer.setCollapsed(state.collapsed!)
        if state.collapsed! {
            contentContainer.alpha = 0
            // TODO: is this accessing the image view before the button's been laid out?
            collapseButton.imageView!.transform = CGAffineTransform(rotationAngle: 0)
            collapseButton.accessibilityLabel = NSLocalizedString("Expand Status", comment: "expand status button accessibility label")
        } else {
            contentContainer.alpha = 1
            collapseButton.imageView!.transform = CGAffineTransform(rotationAngle: .pi)
            collapseButton.accessibilityLabel = NSLocalizedString("Collapse Status", comment: "collapse status button accessibility label")
        }
    }
    
    // MARK: Interaction
    
    @objc private func collapseButtonPressed() {
        statusState.collapsed!.toggle()
        contentContainer.layer.masksToBounds = true
        delegate?.statusEditCellNeedsReconfigure(self, animated: true) {
            self.contentContainer.layer.masksToBounds = false
        }
    }
    
}

extension StatusEditCollectionViewCell: AttachmentViewDelegate {
    func attachmentViewGallery(startingAt index: Int) -> GalleryViewController? {
        guard let delegate else {
            return nil
        }
        let attachments = contentContainer.attachmentsView.attachments!
        let sourceViews = attachments.map {
            contentContainer.attachmentsView.getAttachmentView(for: $0)
        }
        let gallery = delegate.gallery(attachments: attachments, sourceViews: sourceViews, startIndex: index)
        return gallery
    }
    
    func attachmentViewPresent(_ vc: UIViewController, animated: Bool) {
        delegate?.present(vc, animated: animated)
    }
}
