import Foundation

/// The single networking seam the whole app codes against. The app builds entirely on
/// `FixtureDSClient` (zero backend); `LiveDSClient` (FU-A) drops in later unchanged.
///
/// `ask(backend:)` keeps `backend` as `String?` (raw AI-ROUTING §4 values) — S2 maps AIProviderID
/// to that string. This shape is locked by AI-ROUTING.md §4 (a documented contract), verified at
/// integration by the FU-B call-shape regression.
public protocol DSClient: Sendable {
    // Auth
    func login(username: String, password: String, totpCode: String?) async throws -> AccessTokenResponse
    func me() async throws -> UserResponse
    func refresh() async throws -> AccessTokenResponse
    func logout() async throws

    // Documents
    func documents(_ query: DocumentListQuery) async throws -> DocumentListResponse
    func document(id: Int) async throws -> DocumentDetailResponse
    func documentContent(id: Int) async throws -> DocumentContentResponse
    func documentTree() async throws -> [DomainTreeNode]
    func categoryCounts() async throws -> CategoryCounts
    func duplicates() async throws -> DuplicatesResponse
    func patchDocument(id: Int, _ update: DocumentUpdate) async throws -> DocumentResponse
    func putContent(id: Int, content: String) async throws
    func deleteDocument(id: Int) async throws

    // Search / Ask
    func search(q: String, mode: SearchMode?, page: Int?, debug: Bool?) async throws -> SearchResponse
    func ask(q: String, limit: Int?, backend: String?, debug: Bool?) async throws -> AskResponse

    // Memos
    func memos(_ query: MemoListQuery) async throws -> MemoListResponse
    func memo(id: Int) async throws -> MemoResponse
    func createMemo(_ create: MemoCreate) async throws -> MemoResponse
    func patchMemo(id: Int, _ update: MemoUpdate) async throws -> MemoResponse
    func pinMemo(id: Int, pinned: Bool) async throws -> MemoResponse
    func archiveMemo(id: Int, archived: Bool) async throws -> MemoResponse
    func toggleMemoTask(id: Int, taskIndex: Int, checked: Bool) async throws -> MemoResponse
    func deleteMemo(id: Int) async throws

    // Digest
    func digest(date: String?, country: String?) async throws -> DigestResponse
}
