//
//  BSUBanner.swift
//  UnityFramework
//
//  Created by Moin Hasan on 5/23/25.
//

import Foundation
import BlueStackSDK
import UIKit

@MainActor
@objc(BSUBanner)
public class BSUBanner: NSObject {
    @objc public var bannerClient: BSUTypeBannerClientRefPointer?
    @objc public var onBannerDidLoadCallback: BSUOnBannerDidLoadCallback?
    @objc public var onBannerDidFailedCallback: BSUOnBannerDidFailedCallback?
    @objc public var onAdClickedCallback: BSUOnAdClickedCallback?
    @objc public var onBannerDidRefreshCallback: BSUOnBannerDidRefreshCallback?
    @objc public var onBannerDidFailToRefreshCallback: BSUOnBannerDidFailToRefreshCallback?
    @objc public var onBannerHideCallback: BSUOnBannerHideCallback?
    @objc public var onBannerDisplayCallback: BSUOnBannerDisplayCallback?

    private var adPosition: BSUAdPosition = .init(rawValue: 0)!
    private var adFrame: CGRect = .zero
    private var bannerAdSize: BSUAdSize?
    private var bannerAdsFactory: BannerView?
    private var bannerView: UIView?
    private var bannerContainerView: UIView?
    private var placementId: String?

    @objc public init(bannerClientReference: BSUTypeBannerClientRefPointer?, placementId: String, adPosition: BSUAdPosition) {
        self.bannerClient = bannerClientReference
        self.adPosition = adPosition
        self.placementId = placementId
        super.init()
    }
    
    private func createBannerAd(_ adSize: String) {
        destroy()
        bannerAdSize = getBannerAdSize(from: adSize)
        bannerAdsFactory = BannerView(adSize: bannerAdSize!.size)
        bannerAdsFactory?.placementID = placementId
        bannerAdsFactory?.delegate = self
        bannerAdsFactory?.viewController = BSUPluginUtil.unityGLViewController()
        // bannerAdsFactory?.startAutoRefresh()
    }

    @objc public func loadAd(withAdSize size: String) {
        createBannerAd(size)
        loadBannerAd(requestOptions: nil)
    }

    @objc public func loadAd(withAdSize size: String, requestOptions requestOptionsRef: BSUTypeRequestOptionsRef) {
        createBannerAd(size)
        let bsuOptions = Unmanaged<BSURequestOptions>.fromOpaque(requestOptionsRef).takeUnretainedValue()
        let sdkOptions = bsuOptions.toSDKRequestOptions()
        loadBannerAd(requestOptions: sdkOptions)
    }

    @objc public func show() {
        showBannerAd()
    }

    @objc public func hide() {
        hideBannerAd()
    }

    @objc public func setPosition(_ adPosition: BSUAdPosition) {
        guard self.adPosition != adPosition else { return }
        self.adPosition = adPosition
        guard let bannerContainerView = self.bannerContainerView else { return }
        bannerContainerView.removeFromSuperview()

        guard let unityView = BSUPluginUtil.unityGLViewController()?.view else { return }
        
        unityView.addSubview(bannerContainerView)
        bannerContainerView.translatesAutoresizingMaskIntoConstraints = false
        self.setupBannerContainerViewConstraints(with: unityView,
                                                 width: self.adFrame.size.width,
                                                 height: self.adFrame.size.height)
        unityView.layoutIfNeeded()
    }

    @objc public func destroy() {
        self.removeBannerView()
        self.removeBannerContainerView()
        self.bannerAdsFactory?.delegate = nil
        self.bannerAdsFactory = nil
    }

    // MARK: - Private Methods

    private func loadBannerAd(requestOptions: RequestOptions?) {
        guard let bannerAdsFactory = self.bannerAdsFactory else { return }
        
        // Remove existing banner views if they exist
        if self.bannerContainerView != nil {
            self.removeBannerView()
            self.removeBannerContainerView()
        }
        
        // Set up new banner container
        self.adFrame = CGRect(x: 0, y: 0,
                              width: self.bannerAdSize!.width,
                              height: self.bannerAdSize!.height)
        self.bannerContainerView = UIView(frame: self.adFrame)
        self.bannerContainerView?.clipsToBounds = true
        
        guard let unityView = BSUPluginUtil.unityGLViewController()?.view else {
            return
        }
        
        // Add to Unity's view hierarchy
        unityView.addSubview(self.bannerContainerView!)
        self.bannerContainerView?.isHidden = true
        self.bannerContainerView?.translatesAutoresizingMaskIntoConstraints = false
        
        // Set constraints
        self.setupBannerContainerViewConstraints(with: unityView,
                                                 width: self.adFrame.size.width,
                                                 height: self.adFrame.size.height)
        unityView.layoutIfNeeded()
        
        print("BSUBanner: loadBannerAd!!")

        // Load the ad
        if requestOptions == nil {
            bannerAdsFactory.load()
        } else {
            bannerAdsFactory.load(requestOptions: requestOptions)
        }
    }

    private func hideBannerAd() {
        guard let bannerContainerView = self.bannerContainerView else { return }
        bannerContainerView.isHidden = true
//        self.bannerAdsFactory?.stopAutoRefresh()
        self.onBannerHideCallback?(self.bannerClient)
    }

    private func showBannerAd() {
        guard let bannerContainerView = self.bannerContainerView else { return }
        bannerContainerView.isHidden = false
//        self.bannerAdsFactory?.startAutoRefresh()
        self.onBannerDisplayCallback?(self.bannerClient)
    }

    private func removeBannerView() {
        guard bannerView != nil else { return }
        bannerView?.removeFromSuperview()
        bannerView = nil
    }

    private func removeBannerContainerView() {
        guard bannerContainerView != nil else { return }
        bannerContainerView?.removeFromSuperview()
        bannerContainerView = nil
    }
    
    private func setupBannerContainerViewConstraints(with view: UIView, width: CGFloat, height: CGFloat) {
        guard let container = bannerContainerView else { return }
        container.translatesAutoresizingMaskIntoConstraints = false

//      let guide = view.safeAreaLayoutGuide // Use safe area anchors for top/bottom
        var isTopPosition: Bool { adPosition.rawValue == 0 } // 0 == top

        NSLayoutConstraint.activate([
            container.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            container.widthAnchor.constraint(equalToConstant: width),
            container.heightAnchor.constraint(equalToConstant: height),
            isTopPosition
                ? container.topAnchor.constraint(equalTo: view.topAnchor) // guide.topAnchor for safe area
                : container.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }

//    private func setupBannerContainerViewConstraints(with view: UIView, width: CGFloat, height: CGFloat) {
//        view.addConstraint(NSLayoutConstraint(item: self.bannerContainerView!,
//                                              attribute: .centerX,
//                                              relatedBy: .equal,
//                                              toItem: view,
//                                              attribute: .centerX,
//                                              multiplier: 1,
//                                              constant: 0))
//        
//        view.addConstraint(NSLayoutConstraint(item: self.bannerContainerView!,
//                                              attribute: .width,
//                                              relatedBy: .equal,
//                                              toItem: nil,
//                                              attribute: .notAnAttribute,
//                                              multiplier: 1,
//                                              constant: width))
//        
//        view.addConstraint(NSLayoutConstraint(item: self.bannerContainerView!,
//                                              attribute: .height,
//                                              relatedBy: .equal,
//                                              toItem: nil,
//                                              attribute: .notAnAttribute,
//                                              multiplier: 1,
//                                              constant: height))
//        
//        let verticalAttribute: NSLayoutConstraint.Attribute = (self.adPosition == .init(rawValue: 0)!) ? .top : .bottom
//        view.addConstraint(NSLayoutConstraint(item: self.bannerContainerView!,
//                                              attribute: verticalAttribute,
//                                              relatedBy: .equal,
//                                              toItem: view,
//                                              attribute: verticalAttribute,
//                                              multiplier: 1,
//                                              constant: 0))
//    }

    private func setupBannerViewConstraints(with view: UIView) {
        guard let bannerView = self.bannerView else { return }
        view.addConstraint(NSLayoutConstraint(item: bannerView,
                                              attribute: .centerX,
                                              relatedBy: .equal,
                                              toItem: view,
                                              attribute: .centerX,
                                              multiplier: 1,
                                              constant: 0))
        
        view.addConstraint(NSLayoutConstraint(item: bannerView,
                                              attribute: .centerY,
                                              relatedBy: .equal,
                                              toItem: view,
                                              attribute: .centerY,
                                              multiplier: 1,
                                              constant: 0))
    }
    
    func getBannerAdSize(from string: String?) -> BSUAdSize? {
        switch string {
        case "BANNER":
            return .banner
        case "LARGE_BANNER":
            return .largeBanner
        case "FULL_BANNER":
            return .fullBanner
        case "MEDIUM_RECTANGLE":
            return .mediumRectangle
        case "LEADERBOARD":
            return .leaderboard
        case "DYNAMIC_BANNER":
            return .dynamicBanner
        case "DYNAMIC_LEADERBOARD":
            return .dynamicLeaderboard
        default:
            return .banner
        }
    }
}

// MARK: - BannerViewDelegate

extension BSUBanner: @MainActor BannerViewDelegate {
    public func onLoad(_ bannerView: BlueStackSDK.BannerView, _ preferredHeight: CGFloat) {
//      print("Banner successfully loaded with preferredHeight: \(preferredHeight)")
        self.removeBannerView()
        self.bannerView = bannerView
        self.bannerContainerView?.addSubview(bannerView)
        self.bannerView?.translatesAutoresizingMaskIntoConstraints = false
        if let containerView = self.bannerContainerView {
            self.setupBannerViewConstraints(with: containerView)
            containerView.layoutIfNeeded()
        }
        self.onBannerDidLoadCallback?(self.bannerClient)
    }
    
    public func onFailedToLoad(_ bannerView: BlueStackSDK.BannerView, _ error: any Error) {
//      print("Banner Ad failed to load with error: \(error.localizedDescription)")
        if let nsError = error as NSError? {
            let errorPointer = Unmanaged.passUnretained(nsError).toOpaque()
            self.onBannerDidFailedCallback?(self.bannerClient, errorPointer)
        } else {
            self.onBannerDidFailedCallback?(self.bannerClient, nil)
        }
    }
    
    public func onRefresh(_ bannerView: BlueStackSDK.BannerView) {
//      print("Banner Ad refreshed")
        self.onBannerDidRefreshCallback?(self.bannerClient)
    }
    
    public func onFailedToRefresh(_ bannerView: BlueStackSDK.BannerView, _ error: any Error) {
        print("Banner Ad failed to refresh with error: \(error.localizedDescription)")
        if let nsError = error as NSError? {
            let errorPointer = Unmanaged.passUnretained(nsError).toOpaque()
            self.onBannerDidFailToRefreshCallback?(self.bannerClient, errorPointer)
        } else {
            self.onBannerDidFailToRefreshCallback?(self.bannerClient, nil)
        }
    }
    
    public func onClick(_ bannerView: BlueStackSDK.BannerView) {
//      print("Banner Ad clicked")
        self.onAdClickedCallback?(self.bannerClient)
    }
    
    public func onResize(_ bannerView: BlueStackSDK.BannerView, _ size: CGSize) {
        print("Banner Ad resized to size: \(size)")
    }
}
