#if canImport(Darwin)
import Darwin
#endif
import Foundation

/// Safe resolver for CodexBarCore's SwiftPM resource bundle.
///
/// The autogenerated `Bundle.module` accessor traps at launch when the packaged
/// app does not place `CodexBar_CodexBarCore.bundle` at the locations it probes
/// (the app root and the compile-time build directory). The packaged app ships
/// the bundle in `Contents/Resources`, so resolve through the main bundle first
/// and only touch `Bundle.module` after verifying that its development-build
/// candidate exists. Shipped command-line tools resolve the bundle beside the
/// executable; a missing bundle is reported by callers instead of trapping.
public enum CodexBarCoreResources {
    static let missingBundleMessage =
        "CodexBarCore resource bundle is missing next to the executable; reinstall or update CodexBar"

    public static let bundle: Bundle? = resolve(mainBundle: .main)

    static func resolve(
        mainBundle: Bundle,
        executableURL: URL? = nil,
        swiftPMBuildDirectory: URL? = Self.defaultSwiftPMBuildDirectory) -> Bundle?
    {
        let name = "CodexBar_CodexBarCore"
        let bundleName = "\(name).bundle"
        let swiftPMBundleNames = [bundleName, "\(name).resources"]

        if mainBundle.bundleURL.pathExtension == "app" {
            if let url = mainBundle.url(forResource: name, withExtension: "bundle"),
               let bundle = Bundle(url: url)
            {
                return bundle
            }
            if let resourceURL = mainBundle.resourceURL,
               let bundle = Bundle(url: resourceURL.appendingPathComponent(bundleName))
            {
                return bundle
            }
            if let bundle = Bundle(url: mainBundle.bundleURL.appendingPathComponent(bundleName)) {
                return bundle
            }
        }

        let executableDirectory = (executableURL ?? Self.runningExecutableURL(bundle: mainBundle))?
            .resolvingSymlinksInPath()
            .deletingLastPathComponent()
            ?? mainBundle.bundleURL
        for swiftPMBundleName in swiftPMBundleNames {
            let executableCandidate = executableDirectory.appendingPathComponent(swiftPMBundleName)
            if let bundle = Bundle(url: executableCandidate) {
                return bundle
            }
        }

        if let swiftPMBuildDirectory {
            let buildCandidateExists = swiftPMBundleNames.contains { buildBundleName in
                var isDirectory: ObjCBool = false
                let buildCandidate = swiftPMBuildDirectory.appendingPathComponent(buildBundleName)
                return FileManager.default.fileExists(atPath: buildCandidate.path, isDirectory: &isDirectory)
                    && isDirectory.boolValue
            }
            if buildCandidateExists {
                return .module
            }
        }
        return nil
    }

    private static func runningExecutableURL(bundle: Bundle) -> URL? {
        if let executableURL = bundle.executableURL {
            return executableURL
        }

        #if canImport(Darwin)
        var size: UInt32 = 0
        guard _NSGetExecutablePath(nil, &size) != 0 else { return nil }
        var buffer = [Int8](repeating: 0, count: Int(size))
        guard _NSGetExecutablePath(&buffer, &size) == 0 else { return nil }
        let pathBytes = buffer.prefix { $0 != 0 }.map { UInt8(bitPattern: $0) }
        guard let path = String(bytes: pathBytes, encoding: .utf8) else { return nil }
        return URL(fileURLWithPath: path)
        #elseif os(Linux)
        let path = "/proc/self/exe"
        guard FileManager.default.fileExists(atPath: path) else { return nil }
        return URL(fileURLWithPath: path)
        #else
        return nil
        #endif
    }

    private static let defaultSwiftPMBuildDirectory: URL = {
        let packageRoot = URL(fileURLWithPath: #filePath)
            .deletingLastPathComponent() // CodexBarCore
            .deletingLastPathComponent() // Sources
            .deletingLastPathComponent() // package root
        #if DEBUG
        let configuration = "debug"
        #else
        let configuration = "release"
        #endif
        return packageRoot.appendingPathComponent(".build/\(configuration)", isDirectory: true)
    }()
}
