//
//  StoryCell.swift
//  CCSIMobile
//
//  Created by mac on 25/11/21.
//  Copyright © 2021 Milan Savaliya. All rights reserved.
//

import UIKit
import SDWebImage
import AVFoundation
import Async
import Toast_Swift
import WowonderMessengerSDK

protocol StoryPreviewProtocol: AnyObject {
    func segmentedProgressBarReachEnd(cell: StoryCell)
    func segmentedProgressBarReachPrevious(cell: StoryCell)
    func handleStoryBackButtonTap(_ sender: UIButton, cell: StoryCell)
    func handleStoryTrashButtonTap(_ sender: UIButton, cell: StoryCell, story: UserDataStory)
    func handleStorySendMessageTap(_ sender: UIButton, cell: StoryCell, story: UserDataStory)
    func handleStoryViewsCountTap(_ sender: UIButton, cell: StoryCell, story: UserDataStory)
    func handleStoryReactionTap(reaction: Int, cell: StoryCell, story: UserDataStory)
}

final class StoryCell: UICollectionViewCell {
    
    // MARK: - IBOutlet
    
    @IBOutlet weak private var headerView: UIView!
    @IBOutlet weak private var viewProgress: UIView!
    @IBOutlet weak private var imgSnap: UIImageView!
    @IBOutlet weak private var videoView: UIView!
    @IBOutlet weak private var indicatorView: UIActivityIndicatorView!
    @IBOutlet weak var trashButton: UIButton!
    @IBOutlet weak var userProfileImage: UIImageView!
    @IBOutlet weak var lblUserName: UILabel!
    @IBOutlet weak var timeLabel: UILabel!
    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak private var bottomView: UIView!
    @IBOutlet weak var storyCountView: UIView!
    @IBOutlet weak var storyViewsCountLabel: UILabel!
    @IBOutlet weak var storyReplyView: UIView!
    @IBOutlet weak var reactionCollectionView: UICollectionView!
    
    // MARK: - Properties
    
    weak var delegate: StoryPreviewProtocol?
    var progressBar: StoryProgressView?
    var userData: UserData?
    var story: UserDataStory?
    var parentStoryIndex: Int = 0
    var player: AVPlayer!
    private var longGesture: UILongPressGestureRecognizer!
    let reactionGifArray = ["gif_like", "gif_love", "gif_haha", "gif_wow", "gif_sad", "gif_angry"]
    private let timeObserverKeyPath: String = "timeControlStatus"
    
    // MARK: - LifeCycle
    override func awakeFromNib() {
        super.awakeFromNib()
        
        self.setupUI()
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
        self.removeGestureRecognizer(self.longGesture)
        self.progressBar?.resetBar()
        self.resetPlayer()
    }
    
    // MARK: - Selectors
    
    // Back Button Action
    @IBAction func backButtonAction(_ sender: UIButton) {
        self.delegate?.handleStoryBackButtonTap(sender, cell: self)
    }
    
    // Trash Button Action
    @IBAction func trashButtonAction(_ sender: UIButton) {
        if let story = self.story {
            self.delegate?.handleStoryTrashButtonTap(sender, cell: self, story: story)
        }
    }
    
    // Story Views Count Button Action
    @IBAction func storyViewsCountButton(_ sender: UIButton) {
        if let story = self.story {
            self.delegate?.handleStoryViewsCountTap(sender, cell: self, story: story)
        }
    }
    
    // Send Message Button Action
    @IBAction func sendMessageButtonAction(_ sender: UIButton) {
        if let story = self.story {
            self.delegate?.handleStorySendMessageTap(sender, cell: self, story: story)
        }
    }
    
    // MARK: - Helper Function
    
    private func setupUI() {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.touch(_:)))
        self.addGestureRecognizer(tapGesture)
        self.longGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.longPress(_:)))
        self.longGesture.minimumPressDuration = 0.2
        self.collectionViewSetUp()
    }
    
    // Collection View SetUp
    func collectionViewSetUp() {
        self.reactionCollectionView.delegate = self
        self.reactionCollectionView.dataSource = self
        self.reactionCollectionView.register(UINib(resource: R.nib.storyReactionGifCell), forCellWithReuseIdentifier: R.reuseIdentifier.storyReactionGifCell.identifier)
    }
    
    // Set User Data
    func setData() {
        let url = URL(string: self.userData?.avatar ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        self.userProfileImage.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            self.userProfileImage.sd_setImage(with: url, placeholderImage: UIImage(named: ""))
        }
        if let name = self.userData?.name, name != "" {
            self.lblUserName.text = name
        } else if let username = self.userData?.username, username != "" {
            self.lblUserName.text = username
        } else {
            let name = [self.userData?.first_name ?? "", self.userData?.last_name ?? ""].filter({ $0 != "" }).joined(separator: " ")
            self.lblUserName.text = name
        }
        if self.userData?.user_id != AppInstance.instance.userId  ?? "" {
            self.trashButton.isHidden = true
            self.storyCountView.isHidden = true
            self.storyReplyView.isHidden = false
        } else {
            self.trashButton.isHidden = false
            self.storyCountView.isHidden = false
            self.storyReplyView.isHidden = true
        }
    }
    
    func setStoryData(index: Int) {
        self.story = self.userData?.stories?.get(at: index)
        self.timeLabel.text = self.story?.time_text ?? ""
        self.descriptionLabel.text = self.story?.description ?? ""
        if self.userData?.user_id == AppInstance.instance.userId  ?? "" {
            self.storyViewsCountLabel.text = "\(self.story?.view_count ?? 0)"
        }
        self.resetPlayer()
        if (self.story?.videos?.isEmpty ?? false) {
            self.loadImage(urlString: self.story?.thumbnail ?? "")
        } else {
            self.loadVideo(urlString: self.story?.videos?.get(at: 0)?.filename ?? "")
        }
        self.fetchData(id: self.story?.id?.stringValue ?? "")
    }
    
    func initProgressbar() {
        self.progressBar = StoryProgressView(arrayStories: self.userData?.stories?.count ?? 0)
        self.progressBar?.delegate = self
        self.progressBar?.frame = CGRect(x: 0, y: 0, width: frame.width, height: 4)
        self.viewProgress.subviews.forEach { $0.removeFromSuperview() }
        self.viewProgress.addSubview(self.progressBar!)
    }
    
    func loadImage(urlString: String) {
        self.videoView.isHidden = true
        self.imgSnap.isHidden = false
        self.imgSnap.image = nil
        self.indicatorView.isHidden = false
        self.indicatorView.startAnimating()
        self.progressBar?.pause()
        self.progressBar?.duration = 0.005
        self.removeGestureRecognizer(self.longGesture)
        if let url = URL(string: urlString) {
            self.imgSnap.sd_setImage(with: url) { image, error, cache, url in
                if let error = error {
                    print(error.localizedDescription)
                } else {
                    self.progressBar?.resume()
                    self.indicatorView.stopAnimating()
                    self.indicatorView.isHidden = true
                    self.addGestureRecognizer(self.longGesture)
                }
            }
        }
    }
    
    private func resetPlayer() {
        if player != nil {
            self.pauseVideo()
            player.replaceCurrentItem(with: nil)
            self.videoView.layer.sublayers?.removeAll()
            if player.observationInfo != nil {
                NotificationCenter.default.removeObserver(self)
            }
            player = nil
        }
    }
    
    func playVideo() {
        if self.player != nil {
            self.player.play()
        }
    }
    
    func pauseVideo() {
        if self.player != nil {
            self.player.pause()
        }
    }
    
    func loadVideo(urlString: String) {
        self.removeGestureRecognizer(self.longGesture)
        self.indicatorView.startAnimating()
        self.indicatorView.isHidden = false
        self.progressBar?.pause()
        if let url = URL(string: urlString) {
            let asset = AVAsset(url: url)
            let duration = asset.duration
            let durationTime = CMTimeGetSeconds(duration)
            self.progressBar?.duration = 0.025 / durationTime
        }
        self.videoView.isHidden = false
        self.imgSnap.isHidden = true
        guard let url = NSURL(string: urlString) as URL? else {return}
        self.player = AVPlayer(url: url)
        let videoLayer = AVPlayerLayer(player: self.player)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            videoLayer.frame = self.contentView.frame
            videoLayer.videoGravity = .resizeAspect
            self.videoView.layer.addSublayer(videoLayer)
        }
        self.player.addObserver(self, forKeyPath: timeObserverKeyPath, options: [.old, .new], context: nil)
        self.playVideo()
    }
    
    @objc private func longPress(_ sender: UILongPressGestureRecognizer) {
        if sender.state == .began {
            self.progressBar?.isHidden = true
            self.headerView.isHidden = true
            self.descriptionLabel.isHidden = true
            self.bottomView.isHidden = true
            self.pauseVideo()
            self.progressBar?.pause()
        } else if sender.state == .ended {
            self.progressBar?.isHidden = false
            self.headerView.isHidden = false
            self.bottomView.isHidden = false
            self.descriptionLabel.isHidden = false
            self.playVideo()
            self.progressBar?.resume()
        }
    }
    
    @objc private func touch(_ sender: UITapGestureRecognizer) {
        let touch = sender.location(in: self)
        let screenWidthOneThird = self.frame.width / 3
        let absoluteTouch = touch.x
        if absoluteTouch < screenWidthOneThird {
            self.progressBar?.rewind()
        } else {
            self.progressBar?.skip()
        }
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
        guard self.player.observationInfo != nil else { return }
        if keyPath == "timeControlStatus",
           let change = change,
           let newValue = change[NSKeyValueChangeKey.newKey] as? Int,
           let oldValue = change[NSKeyValueChangeKey.oldKey] as? Int {
            let oldStatus = AVPlayer.TimeControlStatus(rawValue: oldValue)
            let newStatus = AVPlayer.TimeControlStatus(rawValue: newValue)
            if newStatus != oldStatus {
                if newStatus == .playing {
                    player.seek(to: .zero)
                    player.removeObserver(self, forKeyPath: timeObserverKeyPath)
                    self.indicatorView.stopAnimating()
                    self.indicatorView.isHidden = true
                    self.progressBar?.resume()
                    self.addGestureRecognizer(self.longGesture)
                }
            }
        }
    }
    
}

// MARK: Collection View SetUp
extension StoryCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.reactionGifArray.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = self.reactionCollectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.storyReactionGifCell.identifier, for: indexPath) as! StoryReactionGifCell
        let gif = self.reactionGifArray[indexPath.item]
        cell.delegate = self
        cell.reactionButton.tag = indexPath.row + 1
        cell.setReactionGif(gif: gif)
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if let story = self.story {
            self.delegate?.handleStoryReactionTap(reaction: (indexPath.item + 1), cell: self, story: story)
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let totalWidth = collectionView.frame.width - 48
        let totalCellWidth = collectionView.height * CGFloat(self.reactionGifArray.count)
        if CGFloat(totalCellWidth) < totalCellWidth {
            return CGSize(width: collectionView.height, height: collectionView.height)
        } else {
            let width = totalWidth * collectionView.height / CGFloat(totalCellWidth)
            return CGSize(width: width, height: width)
        }
    }
    
}

extension StoryCell: StoryReactionGifCellDelegate {
    
    func handleReactionButtonTap(_ sender: UIButton) {
        if let story = self.story {
            self.delegate?.handleStoryReactionTap(reaction: (sender.tag), cell: self, story: story)
        }
    }
    
}

// MARK: SegmentedProgressBarDelegate
extension StoryCell: SegmentedProgressBarDelegate {
    
    func segmentedProgressBarReachEnd() {
        self.delegate?.segmentedProgressBarReachEnd(cell: self)
    }
    
    func segmentedProgressBarReachPrevious() {
        self.delegate?.segmentedProgressBarReachPrevious(cell: self)
    }
    
    func segmentedProgressBarChangedIndex(index: Int) {
        self.setStoryData(index: index)
    }
    
}

// MARK: Api Call
extension StoryCell {
    
    private func fetchData(id: String) {
        if Connectivity.isConnectedToNetwork() {
            Async.background {
                StoriesManager.instance.getStoryById(session_Token: AppInstance.instance.sessionId ?? "", id: id) { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            print(success?.story as Any)
                        }
                    } else if sessionError != nil {
                        Async.main {
                            print(sessionError?.errors?.error_text ?? "")
                        }
                    } else if serverError != nil {
                        Async.main {
                            print(serverError?.errors?.error_text ?? "")
                        }
                    } else {
                        Async.main {
                            print(error?.localizedDescription ?? "")
                        }
                    }
                }
            }
        } else {
            print(InterNetError)
        }
    }
    
}
