import Foundation

/// Open-source license / attribution text bundled with PunktfunkKit (see `Resources/`).
///
/// Exposed from the kit so the app shell can show an Acknowledgements screen. The text files are
/// bundled as SwiftPM resources and read via `Bundle.module`, which works both for `swift build`
/// and for the Xcode app (it links the PunktfunkKit product, so the resource bundle rides along).
public enum Licenses {
    private static func resource(_ name: String) -> String {
        guard let url = Bundle.module.url(forResource: name, withExtension: "txt"),
            let text = try? String(contentsOf: url, encoding: .utf8)
        else { return "" }
        return text
    }

    /// Punktfunk's own license — MIT OR Apache-2.0, at your option.
    public static var appLicense: String {
        let mit = resource("LICENSE-MIT")
        let apache = resource("LICENSE-APACHE")
        if mit.isEmpty && apache.isEmpty {
            return "Punktfunk is licensed under MIT OR Apache-2.0, at your option."
        }
        return "Punktfunk is licensed under MIT OR Apache-2.0, at your option.\n\n"
            + "================================ MIT ================================\n\n"
            + mit
            + "\n\n============================== Apache-2.0 ==============================\n\n"
            + apache
    }

    /// The bundled brand typeface (Geist Sans + Geist Mono) — SIL Open Font License 1.1. The
    /// license file ships alongside the OTFs in `Resources/Fonts/`, satisfying the OFL's
    /// distribution requirement; this surfaces it in the Acknowledgements screen too.
    public static var fontLicense: String {
        guard let url = Bundle.module.url(
            forResource: "Geist-OFL", withExtension: "txt", subdirectory: "Fonts"),
            let text = try? String(contentsOf: url, encoding: .utf8)
        else { return "" }
        return text
    }

    /// Third-party software notices for the linked Rust crates (generated by
    /// `scripts/gen-third-party-notices.sh`).
    public static var thirdPartyNotices: String {
        let text = resource("THIRD-PARTY-NOTICES")
        return text.isEmpty ? "Third-party notices unavailable." : text
    }

    /// `thirdPartyNotices` pre-split into render-sized line chunks. The full notices are ~885 KB /
    /// 16k lines; a single SwiftUI `Text` that large overshoots CoreText/CoreAnimation's max
    /// renderable height — it lays out for ages and draws blank past the limit — so the
    /// Acknowledgements screen renders these chunks in a `LazyVStack` (only on-screen chunks lay
    /// out, and no chunk is tall enough to clip). Split at line boundaries and joined with "\n";
    /// the inter-chunk break is the `LazyVStack` row boundary, so no text is lost. Computed once.
    public static let thirdPartyNoticesChunks: [String] = chunked(thirdPartyNotices)

    /// Lines per chunk: tvOS reads much smaller chunks — focus is how tvOS scrolls, and each
    /// chunk is one focus stop, so a 200-line chunk (~5 screens tall there) would skip most of
    /// itself per step; ~24 lines ≈ two thirds of a screen reads like a page turn. Elsewhere the
    /// only constraint is the text-render height limit, so chunks stay big.
    private static var chunkLines: Int {
        #if os(tvOS)
        24
        #else
        200
        #endif
    }

    /// `text` split at line boundaries into render/focus-sized chunks (joined with "\n"; the
    /// inter-chunk break is the caller's stack-row boundary, so no text is lost). tvOS pages
    /// focus through these — every license wall on the Acknowledgements screen renders this way.
    public static func chunked(_ text: String) -> [String] {
        let lines = text.split(separator: "\n", omittingEmptySubsequences: false)
        return stride(from: 0, to: lines.count, by: chunkLines).map { start in
            lines[start..<min(start + chunkLines, lines.count)].joined(separator: "\n")
        }
    }
}
