import Foundation
import Testing
@testable import CodexBarCore

struct CodexBarCoreResourcesTests {
    @Test
    func `resolver finds bundled plugin resources outside an app context`() throws {
        let bundle = try #require(CodexBarCoreResources.bundle)
        #expect(bundle.url(forResource: "provider-plugin-prelude", withExtension: "js") != nil)
    }

    @Test
    func `resolver prefers the packaged Contents Resources bundle inside an app context`() throws {
        // Build a fake .app that mirrors the packaged layout: the resource
        // bundle lives in Contents/Resources, NOT at the app root — the exact
        // shape that made the autogenerated accessor trap at launch (#2738).
        let root = FileManager.default.temporaryDirectory
            .appendingPathComponent("CodexBarCoreResourcesTests-\(UUID().uuidString)")
        let appURL = root.appendingPathComponent("Fake.app")
        let resourcesURL = appURL.appendingPathComponent("Contents/Resources")
        try FileManager.default.createDirectory(at: resourcesURL, withIntermediateDirectories: true)
        defer { try? FileManager.default.removeItem(at: root) }

        let target = resourcesURL.appendingPathComponent("CodexBar_CodexBarCore.bundle")
        // `Bundle.module` here is the *test* module's bundle; source the copy from
        // CodexBarCore's own resolved bundle (non-app context, proven by the test above).
        let sourceBundle = try #require(CodexBarCoreResources.bundle)
        try FileManager.default.copyItem(at: sourceBundle.bundleURL.resolvingSymlinksInPath(), to: target)

        let fakeApp = try #require(Bundle(url: appURL))
        let resolved = try #require(CodexBarCoreResources.resolve(mainBundle: fakeApp))
        #expect(resolved.bundleURL.path.contains("Contents/Resources/CodexBar_CodexBarCore.bundle"))
        #expect(resolved.url(forResource: "provider-plugin-prelude", withExtension: "js") != nil)
    }

    @Test(arguments: ["bundle", "resources"])
    func `resolver finds an executable adjacent resource bundle`(pathExtension: String) throws {
        let root = FileManager.default.temporaryDirectory
            .appendingPathComponent("CodexBarCoreResourcesCLITests-\(UUID().uuidString)")
        try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
        defer { try? FileManager.default.removeItem(at: root) }

        let sourceBundle = try #require(CodexBarCoreResources.bundle)
        let target = root.appendingPathComponent("CodexBar_CodexBarCore.\(pathExtension)")
        try FileManager.default.copyItem(at: sourceBundle.bundleURL.resolvingSymlinksInPath(), to: target)

        let resolved = try #require(CodexBarCoreResources.resolve(
            mainBundle: .main,
            executableBundleURL: root,
            swiftPMBuildDirectory: nil))
        #expect(resolved.bundleURL.resolvingSymlinksInPath() == target.resolvingSymlinksInPath())
    }

    @Test
    func `resolver returns nil when executable and build bundles are missing`() throws {
        let root = FileManager.default.temporaryDirectory
            .appendingPathComponent("CodexBarCoreResourcesMissingTests-\(UUID().uuidString)")
        try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
        defer { try? FileManager.default.removeItem(at: root) }

        #expect(CodexBarCoreResources.resolve(
            mainBundle: .main,
            executableBundleURL: root,
            swiftPMBuildDirectory: nil) == nil)
    }

    @Test
    func `resource smoke probe reports no failures in a dev context`() {
        // The same probe the packaging launch smoke check runs inside the
        // packaged app (CODEXBAR_RESOURCE_SMOKE=1, #2738).
        #expect(CodexBarCoreResourceSmoke.failures().isEmpty)
    }

    @Test
    func `no raw Bundle module accessor usage in CodexBarCore sources`() throws {
        // The autogenerated accessor fatals when the packaged app lacks a
        // root-level copy of the bundle; all resource loads must go through
        // CodexBarCoreResources. Guard against regressions at the source level.
        let sourcesRoot = URL(fileURLWithPath: #filePath)
            .deletingLastPathComponent() // CodexBarTests
            .deletingLastPathComponent() // Tests
            .deletingLastPathComponent() // repo root
            .appendingPathComponent("Sources/CodexBarCore")
        let enumerator = try #require(FileManager.default.enumerator(
            at: sourcesRoot,
            includingPropertiesForKeys: nil))
        var offenders: [String] = []
        for case let url as URL in enumerator where url.pathExtension == "swift" {
            guard url.lastPathComponent != "CodexBarCoreResources.swift" else { continue }
            let text = try String(contentsOf: url, encoding: .utf8)
            for (index, line) in text.split(separator: "\n", omittingEmptySubsequences: false).enumerated()
                where line.contains("Bundle.module") && !line.trimmingCharacters(in: .whitespaces).hasPrefix("//")
            {
                offenders.append("\(url.lastPathComponent):\(index + 1)")
            }
        }
        #expect(offenders.isEmpty, "raw Bundle.module usage in CodexBarCore: \(offenders)")
    }
}
