//
//  CircleStory.swift
//  react-native-firework-sdk
//

import FireworkVideo
import UIKit

@objc
public enum CircleStorySourceType: Int {
    case discover, channel, playlist, playlistGroup, dynamicContent, hashtagPlaylist, sku, singleContent
}

public protocol CircleStoryDelegate: AnyObject {
    /// Called once after a circle story has been successfully loaded.
    func circleStoryDidLoadFeed(_ view: CircleStory)
    /// Called if the circle story failed to load.
    func circleStory(_ view: CircleStory, didFailToLoadFeed error: VideoFeedError)
}

@objc
public class CircleStory: UIView, VideoFeedViewControllerDelegate, PictureInPictureControllerDelegate {
    @objc public var sourceType: CircleStorySourceType = .discover
    @objc public var channel: String = ""
    @objc public var playlist: String = ""
    @objc public var playlistGroup: String = ""
    @objc public var dynamicContentParameters: NSDictionary = NSDictionary()
    @objc public var hashtagFilterExpression: String = ""
    @objc public var productIds: NSArray = NSArray()
    @objc public var contentId: String = ""
    @objc public var adConfiguration: AdConfiguration?
    @objc public var circleStoryConfiguration: CircleStoryConfiguration? {
        didSet {
            updateCircleStoryViewConfiguration()
        }
    }
    @objc public var videoPlayerConfiguration: VideoPlayerConfiguration? {
        didSet {
            updateCircleStoryViewConfiguration()
            guard let circleStoryView = circleStoryView else {
                return
            }
            circleStoryView.isPictureInPictureEnabled = videoPlayerConfiguration?.enablePictureInPicture ?? false
        }
    }

    @objc var onCircleStoryLoadFinished: RCTBubblingEventBlock?
    @objc var onCircleStoryEmpty: RCTBubblingEventBlock?

    @objc var onCircleStoryDidStartPictureInPicture: RCTBubblingEventBlock?

    @objc var onCircleStoryDidStopPictureInPicture: RCTBubblingEventBlock?

    @objc var onCircleStoryGetFeedId: RCTBubblingEventBlock?

    public weak var delegate: CircleStoryDelegate?

    private var circleStoryView: CircleStoryView?

    private var isInPip: Bool = false

    private var source: VideoFeedContentSource {
        switch sourceType {
        case .discover:
            return .discover
        case .channel:
            return .channel(channelID: channel)
        case .playlist:
            return .channelPlaylist(channelID: channel, playlistID: playlist)
        case .playlistGroup:
            return .playlistGroup(groupID: playlistGroup)
        case .dynamicContent:
            let parameters = dynamicContentParameters as? [String: [String]]
            return .dynamicContent(channelID: channel, parameters: parameters ?? [:])
        case .hashtagPlaylist:
            return .hashtagPlaylist(channelID: channel, filterExpression: hashtagFilterExpression)
        case .sku:
            return .skuPlaylist(channelID: channel, productIDs: (productIds as? [String]) ?? [])
        case .singleContent:
            return .singleContent(contentID: contentId)
        }
    }

    private var circleStoryLayout: CircleStoryLayout {
        guard let circleStoryConfiguration = circleStoryConfiguration else {
            return CircleStoryLayout()
        }

        return circleStoryConfiguration.toNativeLayout()
    }

    public override func layoutSubviews() {
        super.layoutSubviews()
        embed()
    }

    private func embed() {
        guard self.circleStoryView == nil else {
            return
        }

        let circleStoryView = CircleStoryView(layout: circleStoryLayout, source: source)
        circleStoryView.translatesAutoresizingMaskIntoConstraints = false
        circleStoryView.viewConfiguration = convertToCircleStoryContentConfiguration()
        circleStoryView.delegate = self
        circleStoryView.pictureInPictureDelegate = self
        circleStoryView.isPictureInPictureEnabled = videoPlayerConfiguration?.enablePictureInPicture ?? false
        addSubview(circleStoryView)
        NSLayoutConstraint.activate(
            circleStoryView.constraints(equalTo: self)
        )

        onCircleStoryGetFeedId?(["feedId": circleStoryView.feedID])
        self.circleStoryView = circleStoryView
    }

    public override func removeFromSuperview() {
        super.removeFromSuperview()

        guard let circleStoryView = self.circleStoryView else {
            return
        }

        if !isInPip {
            circleStoryView.isPictureInPictureEnabled = false
        }

        circleStoryView.removeFromSuperview()
        self.circleStoryView = nil
    }

    @objc
    public func refresh() {
        guard let circleStoryView = self.circleStoryView else {
            return
        }
        circleStoryView.refresh()
    }

    private func updateCircleStoryViewConfiguration() {
        guard let circleStoryView = circleStoryView else {
            return
        }

        circleStoryView.layout = circleStoryLayout
        circleStoryView.viewConfiguration = convertToCircleStoryContentConfiguration()
    }

    private func convertToCircleStoryContentConfiguration() -> CircleStoryContentConfiguration {
        var resultConfig = circleStoryConfiguration?.toNativeConfiguration() ?? CircleStoryContentConfiguration()
        if let videoPlayerConfiguration = videoPlayerConfiguration,
           let nativePlayerConfig = VideoFeed.convertToVideoPlayerContentConfiguration(videoPlayerConfiguration) {
            resultConfig.playerView = nativePlayerConfig
        }
        // The first launch mute behavior comes from the SDK init options, so apply
        // it here as well; otherwise it would be skipped whenever JS provides no
        // videoPlayerConfiguration.
        VideoFeed.applyVideoLaunchBehavior(to: &resultConfig.playerView)

        return resultConfig
    }

    // MARK: VideoFeedViewControllerDelegate
    public func videoFeedDidLoadFeed(_ viewController: VideoFeedViewController) {
        guard let delegate = self.delegate else {
            return
        }
        delegate.circleStoryDidLoadFeed(self)
    }

    public func videoFeed(
        _ viewController: VideoFeedViewController, didFailToLoadFeed error: VideoFeedError
    ) {
        guard let delegate = self.delegate else {
            return
        }
        delegate.circleStory(self, didFailToLoadFeed: error)
    }

    public func videoFeed(
        _ viewController: VideoFeedViewController,
        didTapFeedItem feedItemDetails: FeedEventDetails
    ) -> Bool {
        return false
    }

    // MARK: PictureInPictureDelegate

    public func pictureInPictureControllerWillStartPictureInPicture(
        _ pictureInPictureController: FireworkVideo.PictureInPictureController
    ) {
    }

    public func pictureInPictureControllerDidStartPictureInPicture(
        _ pictureInPictureController: FireworkVideo.PictureInPictureController
    ) {
        self.onCircleStoryDidStartPictureInPicture?(nil)
        isInPip = true
    }

    public func pictureInPictureController(
        _ pictureInPictureController: FireworkVideo.PictureInPictureController,
        failedToStartPictureInPictureWithError error: Error?
    ) {
    }

    public func pictureInPictureControllerWillStopPictureInPicture(
        _ pictureInPictureController: FireworkVideo.PictureInPictureController
    ) {
    }

    public func pictureInPictureControllerDidStopPictureInPicture(
        _ pictureInPictureController: FireworkVideo.PictureInPictureController
    ) {
        self.onCircleStoryDidStopPictureInPicture?(nil)
        isInPip = false
    }

    public func pictureInPictureController(
        _ pictureInPictureController: FireworkVideo.PictureInPictureController,
        restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
    ) {
        completionHandler(true)
    }
}
