import UIKit
import ComplyCubeMobileSDK
import Foundation

final class CCubeViewControllerV2: UIViewController {
   private let deps = ComplyCubeConfigurationFactory().makeDependencies()
   
   // stash the raw config until the VC is on-screen
    internal var pendingRaw: [String: Any]?

    internal func traceCallback(_ name: String, payload: Any? = nil) {
       if let payload {
           NSLog("[CCubeViewControllerV2][callback] %@ payload=%@", name, String(describing: payload))
       } else {
           NSLog("[CCubeViewControllerV2][callback] %@", name)
       }
   }
   
   func open(raw: [String: Any]) {
       pendingRaw = raw
       if isViewLoaded, view.window != nil { startFlowIfNeeded() }
   }
   
   override func viewDidAppear(_ animated: Bool) {
       super.viewDidAppear(animated)
   }
   
    internal func startFlowIfNeeded() {
       guard let raw = pendingRaw else { return }
       pendingRaw = nil
       do {
           let settings = try ComplyCubeSettings.make(from: raw, deps: self.deps)
           NSLog("[CCViewController] done: Stages Count=%d", settings.stages.count)
           NSLog("[CCViewController] done: Stages WorkflowId= %@", String(describing: settings.workflowTemplateId))
           if let wf = settings.workflowTemplateId, !wf.isEmpty {
               let flow = ComplyCubeMobileSDK.FlowBuilder()
                   .withSDKToken(settings.clientToken)
                   .withClientId(settings.clientID)
                   .withWorkflowId(wf)
                   .withCallbackHandler(self)
               if let scheme = settings.colorScheme { _ = flow.withColorScheme(scheme) }
               if let look   = settings.lookAndFeel  { _ = flow.withLookAndFeel(look) }
               try flow.start()
           } else {
               let flow = ComplyCubeMobileSDK.FlowBuilder()
                   .withEventHandler { (event: Event) in
                       CCLog.info("ComplyCube Event", ["event": event.rawValue])
                       self.traceCallback("event", payload: ["event": event.rawValue])
                   }
                   .withCallbackHandler(self)
                   .withClientId(settings.clientID)
                   .withSDKToken(settings.clientToken)
                    .withEnableCompleteScreen(settings.enableComplete?.enableCompleteScreen ?? false, title: settings.enableComplete?.title, message: settings.enableComplete?.message)
                   .withStages(settings.stages)
               if let scheme = settings.colorScheme { _ = flow.withColorScheme(scheme) }
               if let look   = settings.lookAndFeel  { _ = flow.withLookAndFeel(look) }
               try flow.start()
           }
       } catch {
           CCLog.error("ComplyCube settings build failed", ["error": String(describing: error)])
           dismissSelf()
       }
   }
}

// MARK: - Delegate → unified channel
extension CCubeViewControllerV2: ComplyCubeMobileSDKDelegate {
   // Called when ID-only flow succeeds.
   public func onSuccess(_ result: ComplyCubeIDResult) {
       let payload: [String: Any] = ["ids": result.itemList]
       CCLog.info("ComplyCube onSuccess(IDResult)", payload)
       traceCallback("onSuccess(IDResult)", payload: payload)
       dismissSelf()
   }
   
   // Called when full flow succeeds.
   public func onSuccess(_ result: ComplyCubeResult) {
       let payload: [String: Any] = [
           "liveVideoId": result.liveVideoId as Any,
           "livePhotoId": result.livePhotoId as Any,
           "ids": result.ids
       ]
       CCLog.info("ComplyCube onSuccess(Result)", payload)
       traceCallback("onSuccess(Result)", payload: payload)
       dismissSelf()
   }
   
   public func onCancelled(_ error: ComplyCubeError) {
       let payload: [String: Any] = [
           "message": error.message,
           "errorCode": error.errorCode.rawValue,
           "description": error.description
       ]
       CCLog.warn("ComplyCube onCancelled", payload)
       traceCallback("onCancelled", payload: payload)
       dismissSelf()
   }
   
   public func onError(_ errors: [ComplyCubeError]) {
       let payload: [[String: Any]] = errors.map {
           [
               "message": $0.message,
               "errorCode": $0.errorCode.rawValue,
               "description": $0.description
           ]
       }
       CCLog.error("ComplyCube onError (\(errors.count) error(s))", ["errors": payload])
       traceCallback("onError", payload: payload)
       
       // Maintain your "critical" behavior.
       let isCritical = errors.contains { e in
           switch e.errorCode {
           case .expiredToken, .jailbroken: return true
           default: return false
           }
       }
       if isCritical {
           CCLog.warn("ComplyCube critical error – dismissing VC")
           dismissSelf()
       }
   }

    internal func dismissSelf() { self.presentingViewController?.dismiss(animated: true) }

}

enum CCStageName {
   static func name(for stage: ComplyCubeMobileSDKStage) -> String {
       // Fall back to the runtime type name
       let typeName = String(describing: type(of: stage))
       
       // Map common SDK stage types to your canonical labels
       switch typeName {
       case "WelcomeStage":                return "intro"
       case "UserConsentStage":            return "consent"
       case "DocumentStage":               return "documentCapture"
       case "AddressCaptureStage":         return "addressCapture"
       case "AddressStage":                return "address"              // used after POA capture
       case "CustomerInformationStage":    return "customerInfo"
       case "BiometricStage":
           let mode = biometricMode(stage) ?? "unknown"
           return "faceCapture(\(mode))"
       default:
           return typeName // unknown/new types still get logged
       }
   }
   
   // Best-effort reflect to get photo/video (SDK doesn't expose a public getter)
    internal static func biometricMode(_ stage: ComplyCubeMobileSDKStage) -> String? {
       let m = Mirror(reflecting: stage)
       // Try common property labels that SDKs use internally
       for label in ["type", "stageType", "biometricType"] {
           if let child = m.children.first(where: { $0.label == label }) {
               return String(describing: child.value).lowercased()
           }
       }
       return nil
   }
}
