//
//  StatusPollView.swift
//  Tusker
//
//  Created by Shadowfacts on 4/25/21.
//  Copyright © 2021 Shadowfacts. All rights reserved.
//

import UIKit
import Pachyderm

class StatusPollView: UIView, StatusContentPollView {

    private static let formatter: DateComponentsFormatter = {
        let f = DateComponentsFormatter()
        f.includesTimeRemainingPhrase = true
        f.maximumUnitCount = 1
        f.unitsStyle = .full
        f.allowedUnits = [.weekOfMonth, .day, .hour, .minute]
        return f
    }()
    
    weak var mastodonController: MastodonController!
    weak var delegate: TuskerNavigationDelegate?
    
    private var statusID: String!
    private(set) var poll: Poll?
    
    private var optionsView: PollOptionsView!
    private var voteButton: PollVoteButton!
    private var infoLabel: UILabel!
    
    private var canVote = true
    private var animator: UIViewPropertyAnimator!
    private var currentSelectedOptionIndex: Int!
    
    var isTracking: Bool {
        optionsView.isTracking
    }
    
    override init(frame: CGRect) {
        super.init(frame: .zero)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    private func commonInit() {
        backgroundColor = .clear
        
        optionsView = PollOptionsView(frame: .zero)
        optionsView.translatesAutoresizingMaskIntoConstraints = false
        optionsView.checkedOptionsChanged = self.checkedOptionsChanged
        addSubview(optionsView)
        
        infoLabel = UILabel()
        infoLabel.translatesAutoresizingMaskIntoConstraints = false
        infoLabel.textColor = .secondaryLabel
        infoLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .callout), size: 0)
        infoLabel.adjustsFontSizeToFitWidth = true
        addSubview(infoLabel)
        
        voteButton = PollVoteButton()
        voteButton.translatesAutoresizingMaskIntoConstraints = false
        voteButton.addTarget(self, action: #selector(votePressed))
        voteButton.setFont(infoLabel.font)
        voteButton.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
        addSubview(voteButton)
        
        NSLayoutConstraint.activate([
            optionsView.leadingAnchor.constraint(equalTo: leadingAnchor),
            optionsView.trailingAnchor.constraint(equalTo: trailingAnchor),
            optionsView.topAnchor.constraint(equalTo: topAnchor),
            
            infoLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
            infoLabel.topAnchor.constraint(equalTo: optionsView.bottomAnchor),
            infoLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
            infoLabel.trailingAnchor.constraint(equalTo: voteButton.leadingAnchor, constant: -8),
            
            voteButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 44),
            voteButton.trailingAnchor.constraint(equalTo: trailingAnchor),
            voteButton.topAnchor.constraint(equalTo: optionsView.bottomAnchor),
            voteButton.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
        
        accessibilityElements = [optionsView!, infoLabel!, voteButton!]
    }
    
    func updateUI(status: StatusMO, poll: Poll?) {
        self.statusID = status.id
        self.poll = poll
        
        guard let poll = poll else { return }
        
        // poll.voted is nil if there is no user (e.g., public timeline), in which case the poll also cannot be voted upon
        if (poll.voted ?? true) || poll.expired || status.account.id == mastodonController.account?.id {
            canVote = false
        } else {
            canVote = true
        }
        
        optionsView.mastodonController = mastodonController
        optionsView.isEnabled = canVote
        optionsView.updateUI(poll: poll)
        
        var expired = false
        let expiryText: String?
        if let expiresAt = poll.expiresAt {
            if expiresAt > Date() {
                expiryText = StatusPollView.formatter.string(from: Date(), to: expiresAt)
            } else {
                expired = true
                expiryText = nil
            }
        } else {
            expiryText = "Does not expire"
        }
        
        let format = NSLocalizedString("poll votes count", comment: "poll total votes count")
        infoLabel.text = String.localizedStringWithFormat(format, poll.votesCount)
        if let expiryText = expiryText {
            infoLabel.text! += ", \(expiryText)"
        }
        
        if expired {
            voteButton.disabledTitle = "Expired"
        } else if poll.voted ?? false {
            if status.account.id == mastodonController.account?.id {
                voteButton.isHidden = true
            } else {
                voteButton.disabledTitle = "Voted"
            }
        } else if poll.multiple {
            voteButton.disabledTitle = "Select multiple"
        } else {
            voteButton.disabledTitle = "Select one"
        }
        voteButton.isEnabled = false
    }
    
    func estimateHeight(effectiveWidth: CGFloat) -> CGFloat {
        guard poll != nil else { return 0 }
        return optionsView.estimateHeight(effectiveWidth: effectiveWidth) + infoLabel.sizeThatFits(UIView.layoutFittingExpandedSize).height
    }
    
    private func checkedOptionsChanged() {
        voteButton.isEnabled = optionsView.checkedOptionIndices.count > 0
    }
    
    @objc private func votePressed() {
        guard let statusID,
              let poll else {
            return
        }
        
        optionsView.isEnabled = false
        voteButton.isEnabled = false
        voteButton.disabledTitle = "Voted"
        
        UIImpactFeedbackGenerator(style: .light).impactOccurred()
        
        let request = Poll.vote(poll.id, choices: optionsView.checkedOptionIndices)
        mastodonController.run(request) { (response) in
            switch response {
            case let .failure(error):
                DispatchQueue.main.async {
                    self.updateUI(status: self.mastodonController.persistentContainer.status(for: statusID)!, poll: poll)
                    
                    if let delegate = self.delegate {
                        let config = ToastConfiguration(from: error, with: "Error Voting", in: delegate, retryAction: nil)
                        delegate.showToast(configuration: config, animated: true)
                    }
                }
                
            case let .success(poll, _):
                let container = self.mastodonController.persistentContainer
                DispatchQueue.main.async {
                    guard let status = container.status(for: statusID) else {
                        return
                    }
                    status.poll = poll
                    container.save(context: container.viewContext)
                    container.statusSubject.send(status.id)
                }
            }
        }
    }
    
}
