import Flutter
import UIKit
import ScreenProtectorKit

enum ScrennProtectorMethod: String {
    case protectDataLeakageWithBlur
    case protectDataLeakageWithBlurOff
    case protectDataLeakageWithImage
    case protectDataLeakageWithImageOff
    case protectDataLeakageWithColor
    case protectDataLeakageWithColorOff
    case protectDataLeakageOff
    case preventScreenshotOn
    case preventScreenshotOff
    case preventScreenRecordOn
    case preventScreenRecordOff
    case addListener
    case removeListener
    case isRecording
}

public class SwiftScreenProtectorPlugin: NSObject, FlutterPlugin {
    private static var channel: FlutterMethodChannel? = nil
    private let protectKit: ScreenProtectorKit
    private var protectMode: ScreenProtectorMode = .none
    private var isPreventScreenshotEnabled = false

    init(_ screenProtector: ScreenProtectorKit) {
        self.protectKit = screenProtector
    }

    public static func register(with registrar: FlutterPluginRegistrar) {
        SwiftScreenProtectorPlugin.channel = FlutterMethodChannel(name: "screen_protector", binaryMessenger: registrar.messenger())

        let kit = ScreenProtectorKit(window: SwiftScreenProtectorPlugin.keyWindow())
        kit.setRootViewResolver(FlutterRootViewResolver())
        ScreenProtectorKit.initial(with: kit.window?.rootViewController?.view)
        let instance = SwiftScreenProtectorPlugin(kit)
        
        registrar.addMethodCallDelegate(instance, channel: SwiftScreenProtectorPlugin.channel!)
        registrar.addApplicationDelegate(instance)
    }

    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        if Thread.isMainThread {
            handleFunc(call, result: result)
            return
        }
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            self.handleFunc(call, result: result)
        }
    }
    
    public func applicationWillResignActive(_ application: UIApplication) {
        updateWindowIfNeeded()
        applyDataLeakageProtection()
    }

    public func applicationDidBecomeActive(_ application: UIApplication) {
        updateWindowIfNeeded()
        clearDataLeakageProtection()
    }

    deinit {
        updateWindowIfNeeded()
        protectKit.removeAllObserver()
        protectKit.disablePreventScreenshot()
        protectKit.disablePreventScreenRecording()
        clearDataLeakageProtection()
    }
}

private extension SwiftScreenProtectorPlugin {
    func handleFunc(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let args = call.arguments as? Dictionary<String, String>

        switch ScrennProtectorMethod(rawValue: call.method) {
        case .protectDataLeakageWithBlur:
            setDataLeakageProtectMode(.blur)
            result(true)
            break
        case .protectDataLeakageWithBlurOff:
            if case .blur = protectMode {
                protectMode = .none
            }
            protectKit.disableBlurScreen()
            result(true)
            break
        case .protectDataLeakageWithImage:
            setDataLeakageProtectMode(.image(name: args?["name"] ?? "LaunchImage"))
            result(true)
            break
        case .protectDataLeakageWithImageOff:
            if case .image = protectMode {
                protectMode = .none
            }
            protectKit.disableImageScreen()
            result(true)
            break
        case .protectDataLeakageWithColor:
            guard let hexColor = args?["hexColor"] else {
                result(false)
                return
            }
            setDataLeakageProtectMode(.color(hex: hexColor))
            result(true)
            break
        case .protectDataLeakageWithColorOff:
            if case .color = protectMode {
                protectMode = .none
            }
            protectKit.disableColorScreen()
            result(true)
            break
        case .protectDataLeakageOff:
            protectMode = .none
            clearDataLeakageProtection()
            result(true)
            break
        case .preventScreenshotOn:
            isPreventScreenshotEnabled = true
            updateWindowIfNeeded()
            protectKit.enabledPreventScreenshot()
            result(true)
            break
        case .preventScreenshotOff:
            isPreventScreenshotEnabled = false
            updateWindowIfNeeded()
            protectKit.disablePreventScreenshot()
            result(true)
            break
        case .preventScreenRecordOn:
            updateWindowIfNeeded()
            protectKit.enabledPreventScreenRecording()
            result(true)
            break
        case .preventScreenRecordOff:
            updateWindowIfNeeded()
            protectKit.disablePreventScreenRecording()
            result(true)
            break
        case .addListener:
            protectKit.screenshotObserver { [weak channel = SwiftScreenProtectorPlugin.channel] in
                channel?.invokeMethod("onScreenshot", arguments: nil)
            }
            if #available(iOS 11.0, *) {
                protectKit.screenRecordObserver { [weak channel = SwiftScreenProtectorPlugin.channel] isCaptured in
                    channel?.invokeMethod("onScreenRecord", arguments: isCaptured)
                }
            }
            result("listened")
            break
        case .removeListener:
            protectKit.removeAllObserver()
            result("removed")
            break
        case .isRecording:
            if #available(iOS 11.0, *) {
                result(protectKit.screenIsRecording())
            } else {
                result(false)
            }
            break
        default:
            result(false)
            break
        }
    }
    
    func updateWindowIfNeeded() {
        if let window = Self.keyWindow() {
            protectKit.window = window
        }
    }

    func applyDataLeakageProtection() {
        updateWindowIfNeeded()
        clearDataLeakageProtection()
        switch protectMode {
        case .blur:
            protectKit.enabledBlurScreen()
        case let .image(name):
            protectKit.enabledImageScreen(named: name)
        case let .color(hex):
            protectKit.enabledColorScreen(hexColor: hex)
        case .none:
            break
        }
    }

    func clearDataLeakageProtection() {
        protectKit.disableBlurScreen()
        protectKit.disableImageScreen()
        protectKit.disableColorScreen()
    }

    func setDataLeakageProtectMode(_ mode: ScreenProtectorMode) {
        protectMode = mode
        if UIApplication.shared.applicationState != .active {
            applyDataLeakageProtection()
        } else {
            clearDataLeakageProtection()
        }
    }

    static func keyWindow() -> UIWindow? {
        if #available(iOS 13.0, *) {
            return UIApplication.shared.connectedScenes
                .compactMap { $0 as? UIWindowScene }
                .flatMap { $0.windows }
                .first { $0.isKeyWindow }
        }
        return UIApplication.shared.keyWindow
    }
}
