// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.

import UIKit
import SessionUIKit

final class FakeChatView: UIView {
    private let spacing = Values.mediumSpacing
    
    var contentOffset: CGPoint {
        get { return scrollView.contentOffset }
        set { scrollView.contentOffset = newValue }
    }
    
    private lazy var chatBubbles = [
        getChatBubble(withText: "view_fake_chat_bubble_1".localized(), wasSentByCurrentUser: true),
        getChatBubble(withText: "view_fake_chat_bubble_2".localized(), wasSentByCurrentUser: false),
        getChatBubble(withText: "view_fake_chat_bubble_3".localized(), wasSentByCurrentUser: true),
        getChatBubble(withText: "view_fake_chat_bubble_4".localized(), wasSentByCurrentUser: false),
        getChatBubble(withText: "view_fake_chat_bubble_5".localized(), wasSentByCurrentUser: false)
    ]
    
    private lazy var scrollView: UIScrollView = {
        let result = UIScrollView()
        result.showsHorizontalScrollIndicator = false
        result.showsVerticalScrollIndicator = false
        return result
    }()
    
    private static let bubbleWidth = UIDevice.current.isIPad ? CGFloat(468) : CGFloat(224)
    private static let bubbleCornerRadius = CGFloat(10)
    private static let startDelay: TimeInterval = 1
    private static let animationDuration: TimeInterval = 0.4
    private static let chatDelay: TimeInterval = 1.5
    private static let popAnimationStartScale: CGFloat = 0.6
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setUpViewHierarchy()
        animate()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setUpViewHierarchy()
        animate()
    }
    
    private func setUpViewHierarchy() {
        let stackView = UIStackView(arrangedSubviews: chatBubbles)
        stackView.axis = .vertical
        stackView.spacing = spacing
        stackView.alignment = .fill
        let vInset = Values.smallSpacing
        stackView.layoutMargins = UIEdgeInsets(top: vInset, leading: Values.veryLargeSpacing, bottom: vInset, trailing: Values.veryLargeSpacing)
        stackView.isLayoutMarginsRelativeArrangement = true
        scrollView.addSubview(stackView)
        stackView.pin(to: scrollView)
        stackView.set(.width, to: .width, of: scrollView)
        addSubview(scrollView)
        scrollView.pin(to: self)
        let height = chatBubbles.reduce(0) { $0 + $1.systemLayoutSizeFitting(UIView.layoutFittingExpandedSize).height } + CGFloat(chatBubbles.count - 1) * spacing + 2 * vInset
        scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: height)
    }
    
    private func getChatBubble(withText text: String, wasSentByCurrentUser: Bool) -> UIView {
        let result = UIView()
        let bubbleView = UIView()
        bubbleView.set(.width, lessThanOrEqualTo: FakeChatView.bubbleWidth)
        bubbleView.themeShadowColor = .black
        bubbleView.layer.cornerRadius = FakeChatView.bubbleCornerRadius
        bubbleView.layer.shadowRadius = (ThemeManager.currentTheme.interfaceStyle == .light ? 4 : 8)
        bubbleView.layer.shadowOpacity = (ThemeManager.currentTheme.interfaceStyle == .light ? 0.16 : 0.24)
        bubbleView.layer.shadowOffset = CGSize.zero
        
        bubbleView.themeBackgroundColor = (wasSentByCurrentUser ?
            .messageBubble_outgoingBackground :
            .messageBubble_incomingBackground
        )
        
        let label = UILabel()
        label.font = .boldSystemFont(ofSize: Values.mediumFontSize)
        label.text = text
        label.themeTextColor = (wasSentByCurrentUser ?
            .messageBubble_outgoingText :
            .messageBubble_incomingText
        )
        label.lineBreakMode = .byWordWrapping
        label.numberOfLines = 0
        bubbleView.addSubview(label)
        label.pin(to: bubbleView, withInset: 12)
        
        result.addSubview(bubbleView)
        bubbleView.pin(.top, to: .top, of: result)
        result.pin(.bottom, to: .bottom, of: bubbleView)
        
        if wasSentByCurrentUser {
            bubbleView.pin(.trailing, to: .trailing, of: result)
        }
        else {
            result.pin(.leading, to: .leading, of: bubbleView)
        }
        
        return result
    }
    
    private func animate() {
        let animationDuration = FakeChatView.animationDuration
        let delayBetweenMessages = FakeChatView.chatDelay
        chatBubbles.forEach { $0.alpha = 0 }
        
        Timer.scheduledTimer(withTimeInterval: FakeChatView.startDelay, repeats: false) { [weak self] _ in
            self?.showChatBubble(at: 0)
            Timer.scheduledTimer(withTimeInterval: 1.5 * delayBetweenMessages, repeats: false) { _ in
                self?.showChatBubble(at: 1)
                Timer.scheduledTimer(withTimeInterval: 1.5 * delayBetweenMessages, repeats: false) { _ in
                    self?.showChatBubble(at: 2)
                    UIView.animate(withDuration: animationDuration) {
                        guard let self = self else { return }
                        self.scrollView.contentOffset = CGPoint(x: 0, y: self.chatBubbles[0].height() + self.spacing)
                    }
                    Timer.scheduledTimer(withTimeInterval: 1.5 * delayBetweenMessages, repeats: false) { _ in
                        self?.showChatBubble(at: 3)
                        UIView.animate(withDuration: animationDuration) {
                            guard let self = self else { return }
                            self.scrollView.contentOffset = CGPoint(x: 0, y: self.chatBubbles[0].height() + self.spacing + self.chatBubbles[1].height() + self.spacing)
                        }
                        Timer.scheduledTimer(withTimeInterval: delayBetweenMessages, repeats: false) { _ in
                            self?.showChatBubble(at: 4)
                            UIView.animate(withDuration: animationDuration) {
                                guard let self = self else { return }
                                self.scrollView.contentOffset = CGPoint(x: 0, y: self.scrollView.contentSize.height - self.scrollView.bounds.height)
                            }
                        }
                    }
                }
            }
        }
    }
    
    private func showChatBubble(at index: Int) {
        let chatBubble = chatBubbles[index]
        
        UIView.animate(withDuration: FakeChatView.animationDuration) {
            chatBubble.alpha = 1
        }
        let scale = FakeChatView.popAnimationStartScale
        chatBubble.transform = CGAffineTransform(scaleX: scale, y: scale)
        
        UIView.animate(withDuration: FakeChatView.animationDuration, delay: 0, usingSpringWithDamping: 0.68, initialSpringVelocity: 4, options: .curveEaseInOut, animations: {
            chatBubble.transform = CGAffineTransform(scaleX: 1, y: 1)
        }, completion: nil)
    }
}
