//
//  LNDeeplinkManager.swift
//  Lanu
//
//  Created by OneeChan on 2025/12/12.
//

import Foundation

struct LNDeeplinkUrls {
    static let appScheme = "gami"
    
    enum web: String {
        case closeWindow
        case userCancellation
        case page
        case playmateApply
    }
    
    enum app: String {
        case profile
        
        enum qrcode: String {
            case order
        }
    }
    
    enum user: String {
        case category
        case profile
    }
}

extension RawRepresentable where RawValue == String {
    var deeplinkPath: String {
        let fullTypeName = String(reflecting: Self.self)
        let components = fullTypeName.components(separatedBy: CharacterSet(charactersIn: "<>[]()")).first!
        
        var nestedComponents = components.components(separatedBy: ".")
        if nestedComponents.count > 1 {
            // 移除最外层 lanu
            nestedComponents.removeFirst()
        }
        if nestedComponents.count > 1 {
            // 移除 LNDeeplinkUrls
            nestedComponents.removeFirst()
        }
        nestedComponents.append(rawValue)
        return nestedComponents.joined(separator: "/")
    }
}


class LNDeeplinkManager {
    static let shared = LNDeeplinkManager()
    typealias LNDeeplinkHandler<T: Decodable> = (T?) -> Void
    
    private let lock = NSLock()
    private var routerMap: [String: (Data?) -> Void] = [:]
    
    private init() {
        DispatchQueue.global().async { [weak self] in
            guard let self else { return }
            setupWebDeeplink()
            setupProfileDepplink()
            setupOrderDeeplink()
        }
    }
    
    func handleDeepLink(_ url: URL) {
        DispatchQueue.global().async { [weak self] in
            guard let self else { return }
            
            var fullPath = if url.scheme?.lowercased() == LNDeeplinkUrls.appScheme {
                if let host = url.host {
                    "\(host)\(url.path)"
                } else {
                    url.path
                }
            } else {
                url.path
            }
            if fullPath.hasPrefix("/") {
                fullPath = String(fullPath.dropFirst())
            }
            
            let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
            let params: [String: Any] = components?.queryItems?.reduce(into: [String: Any]())
            { partialResult, item in
                partialResult[item.name] = item.value
            } ?? [:]
            
            let jsonData = try? JSONSerialization.data(withJSONObject: params)
            
            lock.lock()
            let handler = routerMap[fullPath]
            lock.unlock()
            
            handler?(jsonData)
        }
    }
    
    func register<T: Decodable>(url: String, handler: @escaping LNDeeplinkHandler<T>) {
        lock.lock()
        routerMap[url] = { data in
            let model: T?
            if let data {
                let decoder = JSONDecoder()
                model = try? decoder.decode(T.self, from: data)
            } else {
                model = nil
            }
            runOnMain {
                handler(model)
            }
        }
        lock.unlock()
    }
    
    func register(url: String, handler: @escaping () -> Void) {
        lock.lock()
        routerMap[url] = { _ in
            runOnMain {
                handler()
            }
        }
        lock.unlock()
    }
}

extension LNDeeplinkManager {
    private func setupWebDeeplink() {
        register(url: LNDeeplinkUrls.web.page.deeplinkPath) { (param: LNWebPageDeeplinkParams?) in
            guard let param, !param.url.isEmpty else { return }
            UIView.appKeyWindow?.pushToWebView(param)
        }
        register(url: LNDeeplinkUrls.web.playmateApply.deeplinkPath) {
            UIView.appKeyWindow?.pushToJoinUs()
        }
    }
    
    private func setupProfileDepplink() {
        register(url: LNDeeplinkUrls.app.profile.deeplinkPath) { (param: LNProfileDeeplinkParams?) in
            guard let param, !param.uid.isEmpty else { return }
            UIView.appKeyWindow?.pushToProfile(uid: param.uid)
        }
        register(url: LNDeeplinkUrls.user.profile.deeplinkPath) { (param: LNProfileDeeplinkParams?) in
            guard let param, !param.id.isEmpty else { return }
            UIView.appKeyWindow?.pushToProfile(uid: param.id)
        }
    }
    
    private func setupOrderDeeplink() {
        register(url: LNDeeplinkUrls.app.qrcode.order.deeplinkPath) { (param: LNORCodeCreateOrderParams?) in
            guard let param, !param.qrcode.isEmpty else { return }
            LNOrderManager.shared.getQRDetail(data: param.qrcode) { res in
                guard let res else { return }
                UIView.appKeyWindow?.pushToCreateOrder(res)
            }
        }
        register(url: LNDeeplinkUrls.user.category.deeplinkPath) { (param: LNUserSkillParams?) in
            guard let param, !param.code.isEmpty else { return }
            LNOrderManager.shared.getQRDetail(data: param.code) { res in
                guard let res else { return }
                UIView.appKeyWindow?.pushToCreateOrder(res)
            }
        }
    }
}
