//
//  File.swift
//  react-native-firework-sdk
//
//  Created by Big Bear Xiong on 2022/4/21.
//

import UIKit
import FireworkVideo

class RCTRootViewPlaceholder: UIView {
    weak var reactViewController: UIViewController?
}

private struct RCTRootViewResult {
    weak var viewController: UIViewController?
    weak var view: RCTRootView?
}

struct RCTRootViewPlaceholderResult {
    weak var viewController: UIViewController?
    weak var view: RCTRootViewPlaceholder?
}

private struct PlayerExitButtonInfo {
    enum ExitButtonType: Int {
        case close, floating
    }
    var button: UIButton
    var type: ExitButtonType
}

@objc(FWNavigatorModule)
class FWNavigatorModule: RCTEventEmitter {
    override func supportedEvents() -> [String]! {
        return [FWEventName.logMessage.rawValue]
    }

    override class func requiresMainQueueSetup() -> Bool {
        return true
    }

    override var methodQueue: DispatchQueue {
        return DispatchQueue.main
    }

    @objc(pushRNContainer:resolver:rejecter:)
    func pushRNContainer(
        _ params: NSDictionary?,
        resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
    ) {
        guard let presentedVC = RCTPresentedViewController() else {
            resolver(false)
            return
        }

        guard let params = params as? [String: Any] else {
            resolver(false)
            return
        }

        guard let pushRNContainerParams = RCTConvert.pushRNContainerParams(params) else {
            resolver(false)
            return
        }

        guard let appKey = pushRNContainerParams.appKey, appKey.count > 0 else {
            resolver(false)
            return
        }

        let containerViewController = FWRNContainerViewController()
        containerViewController.appKey = appKey
        containerViewController.appProps = pushRNContainerParams.appProps ?? [:]
        containerViewController.modalPresentationStyle = .fullScreen

//        if presentedVC.modalPresentationStyle == .custom,
//            let presentingVC = presentedVC.presentingViewController,
//            presentingVC is FireworkVideo.PlayerViewController {
//            containerViewController.modalPresentationStyle = .overFullScreen
//        }

        presentedVC.present(containerViewController, animated: true) {
            resolver(true)
        }
    }

    @objc(popRNContainer:rejecter:)
    func popRNContainer(
        _ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
    ) {
        if let containerVC = RCTPresentedViewController() as? FWRNContainerViewController,
           containerVC.presentingViewController != nil {
            containerVC.dismiss(animated: true) {
                resolver(true)
            }
        } else {
            resolver(false)
        }
    }

    @objc(popNativeContainer:rejecter:)
    func popNativeContainer(
        _ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
    ) {
        FireworkVideoSDK.dismissFullScreenPlayer { result in
            resolver(result)
        }
    }

    @objc(startFloatingPlayer:rejecter:)
    func startFloatingPlayer(
        _ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
    ) {
        FireworkVideoSDK.startPiP { result in
            resolver(result)
        }
    }

    @objc(stopFloatingPlayer:rejecter:)
    func stopFloatingPlayer(
        _ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
    ) {
        let result = FWNavigatorModule.stopFloatingPlayer()
        resolver(result)
    }

    @objc(bringRNContainerToTop:rejecter:)
    func bringRNContainerToTop(
        resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
    ) {
        guard let presentedVC = RCTPresentedViewController() else {
            resolver(false)
            return
        }

        let containerViewController = FWRNPresentContainerViewController()
        containerViewController.modalPresentationStyle = .fullScreen

        guard let rootVC = RCTKeyWindow()?.rootViewController,
              let rootViewResult = FWNavigatorModule.findRCTRootViewResult(rootVC),
              let rootViewVC = rootViewResult.viewController,
              let rootView = rootViewResult.view else {
            resolver(false)
            return
        }

        let childViewControllers = rootView.reactViewController()?.children
        childViewControllers?.forEach { (childViewController) in
            let detachedController = childViewController
            detachedController.willMove(toParent: nil)
            detachedController.removeFromParent()
            containerViewController.addChild(detachedController)
            detachedController.didMove(toParent: containerViewController)
        }

        rootView.removeFromSuperview()
        let placeholderView = RCTRootViewPlaceholder()
        rootViewVC.view = placeholderView
        containerViewController.rootView = rootView
        presentedVC.present(containerViewController, animated: true) {
            if rootView.reactViewController() != containerViewController {
                // Save previous reactViewController
                placeholderView.reactViewController = rootView.reactViewController()
                rootView.setReactViewController(containerViewController)
            }
            resolver(true)
        }
    }

    @objc(bringRNContainerToBottom:rejecter:)
    func bringRNContainerToBottom(
        _ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
    ) {
        if let containerVC = RCTPresentedViewController() as? FWRNPresentContainerViewController,
           let rootView = containerVC.rootView,
           containerVC.presentingViewController != nil {
            guard let rootVC = RCTKeyWindow()?.rootViewController,
                  let rootViewPlaceholderResult = FWNavigatorModule.findRCTRootViewPlaceholderResult(rootVC),
                  let rootViewPlaceholderVC = rootViewPlaceholderResult.viewController,
                  let rootViewPlaceholder = rootViewPlaceholderResult.view else {
                resolver(false)
                return
            }

            let childViewControllers = rootView.reactViewController()?.children
            containerVC.rootView = nil
            containerVC.dismiss(animated: true) {
                childViewControllers?.forEach { (childViewController) in
                    let detachedController = childViewController
                    detachedController.willMove(toParent: nil)
                    detachedController.removeFromParent()
                    rootViewPlaceholderVC.addChild(detachedController)
                    detachedController.didMove(toParent: rootViewPlaceholderVC)
                }
                rootView.removeFromSuperview()
                rootViewPlaceholderVC.view = rootView

                if let reactViewController = rootViewPlaceholder.reactViewController {
                    // Restore previous reactViewController
                    rootView.setReactViewController(reactViewController)
                }
                resolver(true)
            }
        } else {
            resolver(false)
        }
    }

    @objc(tryStartFloatingOrCloseFullScreen:rejecter:)
    func tryStartFloatingOrCloseFullScreen(
        _ resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
    ) {
        FireworkVideoSDK.startPiPOrDismissFullScreenPlayer { result in
            resolver(result)
        }
    }
}

extension FWNavigatorModule {
    private static func findRCTRootViewResult(_ viewController: UIViewController) -> RCTRootViewResult? {
        if let rootView = viewController.view as? RCTRootView {
            return RCTRootViewResult(viewController: viewController, view: rootView)
        }

        for childVC in viewController.children {
            if let result = findRCTRootViewResult(childVC) {
                return result
            }
        }

        return nil
    }
}

extension FWNavigatorModule {
    static func stopFloatingPlayer() -> Bool {
        do {
            try PictureInPictureController.stop()
            return true
        } catch {
            return false
        }
    }

    static func findRCTRootViewPlaceholderResult(
        _ viewController: UIViewController
    ) -> RCTRootViewPlaceholderResult? {
        if let rootViewPlaceholder = viewController.view as? RCTRootViewPlaceholder {
            return RCTRootViewPlaceholderResult(viewController: viewController, view: rootViewPlaceholder)
        }

        for childVC in viewController.children {
            if let result = findRCTRootViewPlaceholderResult(childVC) {
                return result
            }
        }

        return nil
    }
}
