import Foundation

/// `POST /api/scan` response (src/app/api/scan/route.ts). This does NOT
/// persist anything — it only runs the AI extraction and hands back the
/// result. The caller must follow up with `ReceiptsAPI.sync(...)` once the
/// user has reviewed/confirmed the receipt, exactly like the web dashboard's
/// scan → review → save flow.
struct ScanResponse: Decodable {
    let success: Bool
    let receipt: Receipt?
    let receipts: [Receipt]
    let pageCount: Int?
    let sourcePageCount: Int?
    let truncated: Bool?
}

enum ReceiptsAPI {
    /// `POST /api/scan` — uploads one image/PDF for AI extraction. Requires a
    /// verified session (401 `unauthorized` / 403 `email_not_verified`
    /// otherwise) and is subject to the account's monthly/daily scan quota
    /// (402 `scan_limit_reached` / 429 `daily_scan_limit_reached`) — surface
    /// those via `APIError.server(code:...)`.
    static func scan(fileData: Data, fileName: String, mimeType: String) async throws -> ScanResponse {
        let request = APIRequest.multipartFile(
            path: "/api/scan",
            fileName: fileName,
            mimeType: mimeType,
            fileData: fileData
        )
        return try await APIClient.shared.send(request)
    }

    /// `GET /api/receipts` — the signed-in user's receipts, newest first.
    /// `includePreview` pulls the base64 preview image inline for each row —
    /// keep it `false` for list screens and only request it (or fetch a
    /// single id) when actually displaying an image.
    static func list(limit: Int = 100, includePreview: Bool = false) async throws -> [Receipt] {
        var query = [URLQueryItem(name: "limit", value: String(limit))]
        if includePreview { query.append(URLQueryItem(name: "includePreview", value: "1")) }
        let request = APIRequest(path: "/api/receipts", method: .get, query: query)
        let response: ReceiptListResponse = try await APIClient.shared.send(request)
        return response.receipts
    }

    static func get(id: String) async throws -> Receipt? {
        let request = APIRequest(
            path: "/api/receipts",
            method: .get,
            query: [URLQueryItem(name: "id", value: id), URLQueryItem(name: "includePreview", value: "1")]
        )
        let response: ReceiptListResponse = try await APIClient.shared.send(request)
        return response.receipts.first
    }

    /// `POST /api/receipts` — upserts one or more receipts (matched by `id`).
    /// This is how a scanned-and-reviewed receipt actually gets saved.
    @discardableResult
    static func sync(_ receipts: [Receipt]) async throws -> ReceiptSyncResponse {
        let request = try APIRequest.json(path: "/api/receipts", method: .post, body: receipts)
        return try await APIClient.shared.send(request)
    }

    /// `DELETE /api/receipts?id=...`
    static func delete(id: String) async throws {
        let request = APIRequest(
            path: "/api/receipts",
            method: .delete,
            query: [URLQueryItem(name: "id", value: id)]
        )
        try await APIClient.shared.sendDiscardingResponse(request)
    }
}
