import Foundation

/// Builder for the MCMS list-endpoint query parameters.
///
/// Supported by most list endpoints: `query`, `projection`, `sort`, `limit`
/// (server default 1000), `skip`, `next` (cursor = a document `_id`), `distinct`.
/// Stats/log endpoints additionally require `start-time` and accept `end-time`
/// (UTC `yyyy-MM-dd HH:mm:ss`).
struct APIQuery {
    /// Custom Mongo query as `key=value` pairs (joined with commas by the API).
    var query: [String: String] = [:]
    /// Field inclusion/exclusion: `1` include, `0` exclude.
    var projection: [String: Int] = [:]
    /// Sort field → direction (`1` asc, `-1` desc).
    var sort: [String: Int] = [:]
    var limit: Int?
    var skip: Int?
    /// Pagination cursor: excludes all items at/before this `_id`.
    var next: String?
    /// Attribute to fetch unique values for.
    var distinct: String?
    var startTime: Date?
    var endTime: Date?

    static let empty = APIQuery()

    private static let timeFormatter: DateFormatter = {
        let f = DateFormatter()
        f.locale = Locale(identifier: "en_US_POSIX")
        f.timeZone = TimeZone(identifier: "UTC")
        f.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return f
    }()

    /// NOTE: `query`/`projection`/`sort` are flattened with literal `=`/`,`
    /// separators that MCMS uses to split pairs. Keys/values are NOT escaped, so a
    /// key or value that itself contains `=` or `,` will be mis-parsed into the
    /// wrong filter. Current callers only use simple equality on safe field names;
    /// keep it that way (or escape per the MCMS parser's rules) — see field guide §3.8.
    func queryItems() -> [URLQueryItem] {
        var items: [URLQueryItem] = []

        if !query.isEmpty {
            let joined = query.map { "\($0)=\($1)" }.joined(separator: ",")
            items.append(.init(name: "query", value: joined))
        }
        if !projection.isEmpty {
            let joined = projection.map { "\($0)=\($1)" }.joined(separator: ",")
            items.append(.init(name: "projection", value: joined))
        }
        if !sort.isEmpty {
            let joined = sort.map { "\($0)=\($1)" }.joined(separator: ",")
            items.append(.init(name: "sort", value: joined))
        }
        if let limit { items.append(.init(name: "limit", value: "\(limit)")) }
        if let skip { items.append(.init(name: "skip", value: "\(skip)")) }
        if let next { items.append(.init(name: "next", value: next)) }
        if let distinct { items.append(.init(name: "distinct", value: distinct)) }
        if let startTime {
            items.append(.init(name: "start-time", value: Self.timeFormatter.string(from: startTime)))
        }
        if let endTime {
            items.append(.init(name: "end-time", value: Self.timeFormatter.string(from: endTime)))
        }
        return items
    }

    /// Convenience for a recent time window on stats/log endpoints.
    static func window(lastHours hours: Int, limit: Int? = nil) -> APIQuery {
        var q = APIQuery()
        q.startTime = Calendar.current.date(byAdding: .hour, value: -hours, to: Date())
        q.limit = limit
        return q
    }
}
