import Foundation
import CoreMedia
/// Ports src/lib/filename.ts slug rules: lowercase, strip diacritics,
/// non-alphanumeric runs → single hyphen, trim hyphens, empty → "preset".
func captureSlug(_ input: String) -> String {
let folded = input.lowercased()
.folding(options: .diacriticInsensitive, locale: Locale(identifier: "en_US_POSIX"))
var out = ""
var lastHyphen = false
for scalar in folded.unicodeScalars {
let c = Character(scalar)
if c.isASCII && (c.isLetter || c.isNumber) {
out.append(c); lastHyphen = false
} else if !lastHyphen {
out.append("-"); lastHyphen = true
}
}
while out.hasPrefix("-") { out.removeFirst() }
while out.hasSuffix("-") { out.removeLast() }
return out.isEmpty ? "preset" : out
}
private let timestampFormatter: DateFormatter = {
let f = DateFormatter()
f.locale = Locale(identifier: "en_US_POSIX")
f.dateFormat = "yyyyMMdd-HHmmss"
return f
}()
/// `physarum-<preset-slug>-<YYYYMMDD-HHmmss>.<ext>`
func captureFilename(presetName: String, date: Date, ext: String) -> String {
"physarum-\(captureSlug(presetName))-\(timestampFormatter.string(from: date)).\(ext)"
}
/// Even-rounded export dimensions for a width/height aspect at a given long edge.
/// aspectWH >= 1 → width is the long edge; < 1 (portrait) → height is the long edge.
func exportDimensions(aspectWH: Double, longEdge: Int) -> (w: Int, h: Int) {
func even(_ v: Int) -> Int { max(2, v - (v % 2)) }
if aspectWH >= 1 {
return (even(longEdge), even(Int((Double(longEdge) / aspectWH).rounded())))
} else {
return (even(Int((Double(longEdge) * aspectWH).rounded())), even(longEdge))
}
}
func clipFrameCount(durationSeconds: Int, fps: Int) -> Int { max(1, durationSeconds) * max(1, fps) }
func clipPresentationTime(frameIndex: Int, fps: Int) -> CMTime {
CMTime(value: CMTimeValue(frameIndex), timescale: CMTimeScale(max(1, fps)))
}