import { FetchOptions, FetchResponse, ResolvedFetchOptions } from 'ofetch';

// ------------------------------
//             MODELS
// ------------------------------

/**
 * Represents a User within the system.
 * A User typically has a unique identifier and a display name.
 */
interface DeckUser {
    /** Unique identifier for the user in the system */
    primaryKey: string;

    /** Universal unique identifier for the user, typically used across services */
    uid: string;

    /** The display name of the user */
    displayname: string;
}

/**
* Represents the Permissions available for a user or group on a given resource.
* Permissions are typically used to define access control levels.
*/
interface Permissions {
    /** Permission to read the resource */
    PERMISSION_READ: boolean;

    /** Permission to edit the resource */
    PERMISSION_EDIT: boolean;

    /** Permission to manage the resource (e.g., add/remove users, configure settings) */
    PERMISSION_MANAGE: boolean;

    /** Permission to share the resource with others */
    PERMISSION_SHARE: boolean;
}

/**
* Represents the Settings for a user or board, providing customization options.
*/
interface DeckSettings {
    /** Notification setting for due dates, 'on' or 'off' */
    "notify-due": "off" | "on";

    /** Whether the calendar feature is enabled */
    calendar: boolean;
}

/**
* Represents a Label used to categorize or tag elements on a board.
*/
interface Label {
    /** The title or name of the label */
    title: string;

    /** The color of the label, represented as a hex color code */
    color: string;

    /** The ID of the board this label belongs to */
    boardId: number;

    /** The ID of the card this label is associated with, or null if not applicable */
    cardId: number | null;

    /** Unique identifier for the label */
    id: number;
}

/**
* Represents a Board which is a container for stacks and cards.
*/
interface Board {
    /** The title of the board */
    title: string;

    /** The owner of the board, represented by a User object */
    owner: User;

    /** The color of the board, represented as a hex color code */
    color: string;

    /** Whether the board is archived */
    archived: boolean;

    /** List of labels associated with the board */
    labels: Label[];

    /** Access control list (ACL) of the board, containing user IDs or roles with access */
    acl: string[];

    /** The permissions associated with the board */
    permissions: Permissions;

    /** List of users associated with the board, represented by their user IDs */
    users: string[];

    /** Number of users with whom the board is shared */
    shared: number;

    /** Timestamp when the board was deleted (0 if not deleted) */
    deletedAt: number;

    /** Unique identifier for the board */
    id: number;

    /** Timestamp of the last modification made to the board */
    lastModified: number;

    /** Optional settings specific to the board, such as notification preferences */
    settings?: Settings;
}

/**
* Represents a Stack, which is a collection of cards within a board.
*/
interface Stack {
    /** The title or name of the stack */
    title: string;

    /** The ID of the board to which this stack belongs */
    boardId: number;

    /** Timestamp when the stack was deleted (0 if not deleted) */
    deletedAt: number;

    /** Timestamp of the last modification made to the stack */
    lastModified: number;

    /** List of cards within the stack */
    cards: Card[];

    /** Order of the stack relative to others, used for sorting purposes */
    order: number;

    /** Unique identifier for the stack */
    id: number;
}

/**
* Represents a Card, which can be assigned to a stack, and may have various attributes such as title, description, and due date.
*/
interface Card {
    /** The title or name of the card */
    title: string;

    /** The description of the card, can be null if no description is provided */
    description: string | null;

    /** The ID of the stack to which the card belongs */
    stackId: number;

    /** The type of the card, can be 'plain' or other string values for specialized types */
    type: "plain" | string;

    /** Timestamp of the last modification made to the card */
    lastModified: number;

    /** Timestamp of the card creation */
    createdAt: number;

    /** List of labels associated with the card, or null if no labels */
    labels: string[] | null;

    /** List of users assigned to the card, or null if no users are assigned */
    assignedUsers: string[] | null;

    /** List of attachments associated with the card, or null if no attachments */
    attachments: any[] | null;

    /** The number of attachments associated with the card */
    attachmentCount: number | null;

    /** The ID of the user who owns the card */
    owner: string;

    /** The order of the card within the stack, used for sorting */
    order: number;

    /** Whether the card is archived */
    archived: boolean;

    /** The due date of the card in ISO 8601 format, or null if no due date is set */
    duedate: string | null;

    /** Timestamp when the card was deleted (0 if not deleted) */
    deletedAt: number;

    /** The number of unread comments on the card */
    commentsUnread: number;

    /** Unique identifier for the card */
    id: number;

    /** Flag indicating whether the card is overdue (1 if overdue, 0 if not) */
    overdue: number;
}

/**
* Represents an Attachment associated with a card.
* Attachments can be files or other resources linked to the card.
*/
interface Attachment {
    /** The ID of the card this attachment belongs to */
    cardId: number;

    /** The type of attachment (e.g., file, deck file, or custom type) */
    type: 'deck_file' | 'file' | string;

    /** The filename or path of the attachment */
    data: string;

    /** Timestamp when the attachment was last modified */
    lastModified: number;

    /** Timestamp when the attachment was created */
    createdAt: number;

    /** The ID of the user who created the attachment */
    createdBy: string;

    /** Timestamp when the attachment was deleted (0 if not deleted) */
    deletedAt: number;

    /** Additional metadata about the attachment */
    extendedData: {
        /** Size of the attachment in bytes */
        filesize: number;

        /** MIME type of the attachment (e.g., 'image/jpeg', 'application/pdf') */
        mimetype: string;

        /** Information about the file path and name */
        info: {
            /** Directory path of the attachment */
            dirname: string;

            /** Base filename (name + extension) */
            basename: string;

            /** The file extension (e.g., '.jpg', '.pdf') */
            extension: string;

            /** The filename without extension */
            filename: string;
        };
    };

    /** Unique identifier for the attachment */
    id: number;
}



// ------------------------------
//            REQUESTS
// ------------------------------

interface CreateBoardPayload{
    title: string;
    color: string
}

interface UpdateBoardPayload{
    title?: string;
    color?: string;
    archived?: false;
}

interface CreateAclRulePayload {
    type: string; // Type of the participant, [0: User, 1: Group, 7: Circle]
    participant: string; // The uid of the participant
    permissionEdit: boolean; // Setting if the participant has edit permissions
    permissionShare: boolean; // Setting if the participant has sharing permissions
    permissionManage: boolean; // Setting if the participant has management permissions
}

interface CreateStackPayload{
    title: string;
    order: number | 999;
}

interface UpdateStackPayload{
    title?: string;
    order?: number;
}

interface CreateCardPayload {
    title: string;
    type?: string | "plain";
    order?: number;
    description?: string;
    duedate?: string | null;
}

interface UpdateCardPayload {
    title: string;
    type: "plain";
    owner: string;
    order?: number;
    description?: string;
    duedate?: string | null;
}

interface ReorderCardPayload {
    order: number;
    stackId: number;
}
interface CreateLabelPayload {
    title: string;
    color: string; // Assuming color is a hex string (e.g., "31CC7C")
}

interface UpdateLabelPayload {
    title?: string;
    color?: string; // Assuming color is a hex string (e.g., "31CC7C")
}


// ------------------------------
//            RESPONSES
// ------------------------------

interface AclRuleResponse {
    participant: DeckUser; // The participant is a User object
    type: number; // Type of participant (likely an enum or a numeric identifier)
    boardId: number; // The ID of the board the participant is associated with
    permissionEdit: boolean; // Whether the participant has edit permissions
    permissionShare: boolean; // Whether the participant has share permissions
    permissionManage: boolean; // Whether the participant has manage permissions
    owner: boolean; // Whether the participant is the owner of the board
    id: number; // Unique identifier for the participant
}

interface AssignUserResponse{
    id: number;
    participant: {
      primaryKey: string;
      uid: string;
      displayname: string;
    }
    cardId: number;
}

interface ErrorDetails {
    code: number;
    message: string;
    url: string;
    timestamp: string;
    body?: any;
    details?: any;
}
declare class ApiError extends Error {
    statusCode: number;
    errorDetails: ErrorDetails;
    constructor(errorDetails: ErrorDetails, name?: string);
    toString(errorDetails: ErrorDetails): string;
}

interface BasicAuth {
    username: string;
    password: string;
}
interface RequestOptions extends FetchOptions {
    basicAuth?: BasicAuth;
    mapError?: (request: RequestInfo, response: FetchResponse<any>, options: ResolvedFetchOptions) => Promise<ApiError>;
}

declare class BaseApiClient {
    private baseUrl;
    private username;
    private password;
    constructor(baseUrl: string, username: string, password: string);
    protected request<T>(url: string, options: RequestOptions): Promise<T>;
    protected ocsRequest<T>(url: string, options: RequestOptions): Promise<T>;
    protected get<T, Q>(url: string, query?: Q): Promise<T>;
    protected getBlob(url: string): Promise<Blob>;
    protected post<T, R>(url: string, body: T): Promise<R>;
    protected postBlob<T, R>(url: string, body: T): Promise<R>;
    protected put<T, R>(url: string, body: T): Promise<R>;
    protected patch<T, R>(url: string, body: T): Promise<R>;
    protected delete<T>(url: string): Promise<T>;
    protected ocsGet<T, Q>(url: string, query?: Q): Promise<T>;
    protected ocsPost<T, R>(url: string, body: T): Promise<R>;
    protected ocsPut<T, R>(url: string, body: T): Promise<R>;
    protected ocsDelete<T>(url: string): Promise<T>;
    protected buildErrorObject(request: RequestInfo, response: FetchResponse<any>, options: ResolvedFetchOptions): Promise<ApiError>;
    protected buildOcsErrorObject(request: RequestInfo, response: FetchResponse<any>, options: ResolvedFetchOptions): Promise<ApiError>;
}

declare class DeckClient extends BaseApiClient {
    getBoards(details: boolean): Promise<Board[]>;
    createBoard(payload: CreateBoardPayload): Promise<Board>;
    getBoard(boardId: number): Promise<Board>;
    updateBoard(boardId: number, payload: UpdateBoardPayload): Promise<Board>;
    deleteBoard(boardId: number): Promise<void>;
    undoDeleteBoard(boardId: number): Promise<void>;
    createShare(boardId: number, payload: CreateAclRulePayload): Promise<AclRuleResponse>;
    updateShare(boardId: number, aclId: number, payload: CreateAclRulePayload): Promise<AclRuleResponse>;
    deleteShare(boardId: number, aclId: number): Promise<void>;
    getStacks(boardId: number): Promise<Stack[]>;
    getArchivedStacks(boardId: number): Promise<Stack[]>;
    createStack(boardId: number, payload: CreateStackPayload): Promise<Stack>;
    getStack(boardId: number, stackId: number): Promise<Stack>;
    updateStack(boardId: number, stackId: number, payload: UpdateStackPayload): Promise<Stack>;
    deleteStack(boardId: number, stackId: number): Promise<void>;
    createCard(boardId: number, stackId: number, payload: CreateCardPayload): Promise<Card>;
    getCard(boardId: number, stackId: number, cardId: number): Promise<Card>;
    updateCard(boardId: number, stackId: number, cardId: number, payload: UpdateCardPayload): Promise<Card>;
    deleteCard(boardId: number, stackId: number, cardId: number): Promise<void>;
    assignLabelToCard(boardId: number, stackId: number, cardId: number, labelId: number): Promise<void>;
    removeLabelFromCard(boardId: number, stackId: number, cardId: number, labelId: number): Promise<void>;
    assignUserToCard(boardId: number, stackId: number, cardId: number, userId: string): Promise<AssignUserResponse>;
    removeUserFromCard(boardId: number, stackId: number, cardId: number, userId: string): Promise<void>;
    reorderCard(boardId: number, stackId: number, cardId: number, payload: ReorderCardPayload): Promise<void>;
    getLabel(boardId: number, labelId: number): Promise<Label>;
    createLabel(boardId: number, payload: CreateLabelPayload): Promise<Label>;
    updateLabel(boardId: number, labelId: number, payload: UpdateLabelPayload): Promise<Label>;
    deleteLabel(boardId: number, labelId: number): Promise<void>;
    getCardAttachements(boardId: number, stackId: number, cardId: number): Promise<Attachment[]>;
    getCardAttachement(boardId: number, stackId: number, cardId: number, attachementId: number): Promise<Attachment>;
    uploadCardAttachement(boardId: number, stackId: number, cardId: number, file: Blob): Promise<void>;
    updateCardAttachement(boardId: number, stackId: number, cardId: number, attachementId: number, file: Blob): Promise<void>;
    deleteCardAttachement(boardId: number, stackId: number, cardId: number, attachementId: number): Promise<void>;
    restoreCardAttachement(boardId: number, stackId: number, cardId: number, attachementId: number): Promise<void>;
    getConfig(): Promise<DeckSettings>;
    updateConfigKey(configId: string, key: string, value: string): Promise<void>;
    buildOcsErrorObject(request: RequestInfo, response: FetchResponse<any>, options: ResolvedFetchOptions): Promise<ApiError>;
}

//
// *******************************************
//                 MODELS
// *******************************************    


/**
 * Represents a bookmark within Nextcloud.
 */
interface Bookmark {
    /**
     * Unique identifier for the bookmark.
     */
    id: number;

    /**
     * The URL that this bookmark points to. Can be HTTP, FTP, file, or javascript link.
     */
    url: string;

    /**
     * Target URL for the bookmark. Can be HTTP, FTP, file, or javascript link.
     */
    target: string;

    /**
     * Human-readable title of the bookmark.
     */
    title: string;

    /**
     * Detailed description or note about the bookmark.
     */
    description: string;

    /**
     * UNIX timestamp of when the bookmark was created.
     */
    added: number;

    /**
     * ID of the user who owns the bookmark.
     */
    userId: string;

    /**
     * List of tags associated with the bookmark for classification.
     */
    tags: string[];

    /**
     * List of folders this bookmark belongs to.
     */
    folders: string[];

    /**
     * Number of times this bookmark has been clicked or accessed.
     */
    clickCount: number;

    /**
     * Boolean indicating if the bookmark's URL is reachable.
     */
    available: boolean;

    /**
     * HTML content of the bookmarked web page, if available (since v4.2.0).
     * `null` if the content is unavailable or not scraped.
     */
    htmlContent: string | null;

    /**
     * Plain text content of the bookmarked web page, if available (since v4.2.0).
     * `null` if the content is unavailable or not scraped.
     */
    textContent: string | null;

    /**
     * If the bookmark links to a non-HTML file, this is the Nextcloud file ID (since v3.4.0).
     * `null` if no file is associated.
     */
    archivedFile: number | null;
}

/**
 * Represents a folder within the Nextcloud bookmark system.
 */
interface BookmarkFolder {
    /**
     * Unique identifier for the folder.
     */
    id: number;

    /**
     * Human-readable title of the folder.
     */
    title: string;

    /**
     * ID of the parent folder. `0` indicates this is a root folder.
     */
    parentFolderId: number;

    /**
     * ID of the user who owns the folder.
     */
    userId: string;

    /**
     * Display name of the user who owns the folder.
     */
    userDisplayName: string;
}

type FolderTree = FolderTreeNode[]

/**
 * A stripped-down version of a folder, used for displaying folder hierarchies.
 */
interface FolderTreeNode {
    /**
     * Unique identifier for the folder.
     */
    id: number;

    /**
     * Title of the folder.
     */
    title: string;

    /**
     * ID of the parent folder. `0` indicates this is a root folder.
     */
    parentFolderId: number;

    /**
     * List of child folders.
     */
    children: FolderTreeNode[];
}

/**
 * Represents a simplified bookmark used in folder or bookmark APIs.
 */
interface SimpleBookmark {
    /**
     * export type of content, always "bookmark" for this export interface.
     */
    type: 'bookmark';

    /**
     * The unique identifier of the bookmark.
     */
    id: number;

    /**
     * The title of the bookmark.
     */
    title: string;

    /**
     * The URL the bookmark points to.
     */
    url: string;
}

/**
 * Represents a simplified folder used in folder or bookmark APIs.
 */
interface SimpleBookmarkFolder {
    /**
     * export type of content, always "folder" for this export interface.
     */
    type: 'folder';

    /**
     * The unique identifier of the folder.
     */
    id: number;

    /**
     * The title of the folder.
     */
    title: string;

    /**
     * The user ID of the folder's owner.
     */
    userId: string;
}

interface SimpleBookmarkOrderNode {
    type: 'folder' | 'bookmark';
    id: number
    children?: SimpleBookmarkOrderNode[]
}

interface FolderShare {
    id: number,
    folderId: number,
    participant: string,
    type: number,
    canWrite: boolean,
    canShare: boolean
}


/**
 * *******************************************
 *             REQUEST BODYS
 * *******************************************    
 */

/**
 * export interface representing the query parameters for fetching bookmarks.
 */
interface BookmarkSearchParams {

    /**
     * An array of tags that bookmarks should have.
     * If provided, only bookmarks with these tags will be returned.
     */
    tags?: string[];

    /**
     * The page number for paginated results.
     * If non-negative, results will be paginated by the `limit` per page.
     * Default is 0 (first page).
     */
    page?: number;

    /**
     * The number of bookmarks to return per page.
     * Default is 10.
     */
    limit?: number;

    /**
     * The column to sort the results by.
     * One of: 'url', 'title', 'description', 'public', 'lastmodified', 'clickcount'.
     * Default is 'lastmodified'.
     */
    sortby?: 'url' | 'title' | 'description' | 'public' | 'lastmodified' | 'clickcount';

    /**
     * An array of words to search for in the following columns:
     * 'url', 'title', 'description', and 'tags'.
     * Only bookmarks that match any of the provided search terms will be returned.
     */
    search?: string[];

    /**
     * Defines whether all search terms must be present ('and') or if one match is sufficient ('or').
     * Default is 'or'.
     */
    conjunction?: 'and' | 'or';

    /**
     * The ID of the folder to filter bookmarks by.
     * Only bookmarks that are direct children of the folder with the provided ID will be returned.
     * The root folder has ID `-1`.
     */
    folder?: number;

    /**
     * The specific URL to filter bookmarks by.
     * Use this to test whether a URL exists in the user's bookmarks.
     * This feature was added in version 1.0.0.
     */
    url?: string;

    /**
     * If set to true, only dead links (404 or similar status codes) will be returned.
     * This feature was added in version 3.4.0.
     */
    unavailable?: boolean;

    /**
     * If set to true, only bookmarks whose contents have been archived will be returned.
     * This feature was added in version 3.4.0.
     */
    archived?: boolean;

    /**
     * If set to true, only bookmarks that have no tags will be returned.
     * This feature was added in version 0.12.0.
     */
    untagged?: boolean;

    /**
     * If set to true, only bookmarks that exist in multiple folders will be returned.
     * This feature was added in version 10.2.0.
     */
    duplicated?: boolean;
}

/**
 * Represents the query parameters for fetching folders.
 */
interface FolderSearchParams {
    /**
    * The id of the folder whose contents to retrieve (Default: -1, which is the root folder)
    */
    root?: number;

    /**
    * How many layers of folders to return at max. By default, all layers are returned.
    */
    layers?: number;
}

/**
* Represents the request body for creating a new bookmark.
*/
interface CreateBookmarkPayload {
    /**
     * The URL the bookmark points to.
     * Can be an HTTP, FTP, file, or JavaScript link.
     * @required
     */
    url: string;

    /**
     * The title of the bookmark.
     * This should be a short, human-readable label for the bookmark.
     * @optional If absent the title of the html site referenced by url is used
     */
    title?: string;

    /**
     * A detailed description or note for the bookmark.
     * This helps to provide more context about the bookmark.
     * @optional
     */
    description?: string;

    /**
     * Tags associated with the bookmark.
     * Array of tags for this bookmark (these needn’t exist and are created on-the-fly)
     * @optional
     */
    tags?: string[];

    /**
   * Folders associated with the bookmark.
   * An array of IDs of the folders this bookmark should reside in.
   * @optional if absent the new bookmark will be put in the root folder
   */
    folders?: string[];
}

/**
  * Represents the request body for updating an existing bookmark.
  */
interface UpdateBookmarkPayload {
    /**
     * The URL the bookmark points to.
     * Optional field, can be updated if the bookmark URL changes.
     */
    url?: string;

    /**
     * List of tags to be associated with the bookmark.
     * Optional field, used to update the tags of the bookmark.
     */
    tags?: string[];

    /**
     * The title of the bookmark.
     * Optional field, can be updated if the title changes.
     */
    title?: string;

    /**
     * A detailed description of the bookmark.
     * Optional field, can be updated if the description changes.
     */
    description?: string;

    /**
     * A list of folder IDs the bookmark is part of.
     * Optional field, used to update the folders the bookmark is categorized under.
     */
    folders?: number[];
}

/**
* Represents the request body for creating a new bookmark.
*/
interface CreateFolderPayload {
    /**
     * The title of the bookmark.
     * This should be a short, human-readable label for the folder.
     */
    title: string;

    /**
     * The id of the parent folder for the new folder.
     * The root folder is defined by -1.
     */
    parentFolder: number | -1
}

/**
* Represents the request body for creating a new bookmark.
*/
interface CreateFolderPayload {
    /**
     * The title of the bookmark.
     * This should be a short, human-readable label for the folder.
     */
    title: string;

    /**
     * The id of the parent folder for the new folder.
     * The root folder is defined by -1.
     */
    parentFolder?: number | -1
}

/**
* Represents the request body for creating a new bookmark.
*/
interface UpdateFolderPayload {
    /**
     * The title of the bookmark.
     * This should be a short, human-readable label for the folder.
     */
    title?: string;

    /**
     * The id of the parent folder for the new folder.
     * The root folder is defined by -1.
     */
    parentFolder?: number | -1
}

/**
* Represents the request body for creating a Share of a folder.
*/
interface CreateFolderSharePayload {
    /**
     * The id of whom to share.
     */
    participant: string;

    /**
     * The export type of sharee.
     * Currently either 1 if it’s a group, or 0 if it’s a single user;
     */
    type: 0 | 1;

    /**
     * Defines the write access.
     */
    canWrite?: boolean;

    /**
     * Defines the weather this person / group can reshare the resource.
     */
    canShare?: boolean;
}

/**
* Represents the request body for creating a Share of a folder.
*/
interface UpdateFolderSharePayload {
    /**
     * Defines the write access.
     */
    canWrite: boolean;

    /**
     * Defines the weather this person / group can reshare the resource.
     */
    canShare: boolean;
}

/**
* Represents the request body for setting a new order of elements.
*/
interface SetFolderContentOrderPayload {
    data: SimpleBookmarkOrderNode[]
}

/**
 * *******************************************
 *             RESPONSE BODYS
 * *******************************************    
 */

type BookmarkStatus = 'success' | 'error';

declare class BookmarkClient extends BaseApiClient {
    queryBookmarks(query?: BookmarkSearchParams): Promise<Bookmark[]>;
    createBookmark(body: CreateBookmarkPayload): Promise<Bookmark>;
    updateBookmark(bookmarkId: number, body: UpdateBookmarkPayload): Promise<Bookmark>;
    getBookmark(bookmarkId: number): Promise<Bookmark>;
    deleteBookmark(bookmarkId: number): Promise<BookmarkStatus>;
    getBookmarkImage(bookmarkId: number): Promise<Blob>;
    getBookmarkFavicon(bookmarkId: number): Promise<Blob>;
    clickBookmark(bookmarkUrl: string): Promise<BookmarkStatus>;
    getTags(): Promise<string[]>;
    renameTag(tagName: string, newTagName: string): Promise<BookmarkStatus>;
    deleteTag(tagName: string): Promise<BookmarkStatus>;
    getFolderTree(query?: FolderSearchParams): Promise<FolderTree>;
    createFolder(body: CreateFolderPayload): Promise<BookmarkFolder>;
    getFolder(folderId: number): Promise<BookmarkFolder>;
    updateFolder(folderId: number, body: UpdateFolderPayload): Promise<BookmarkFolder>;
    hashFolder(folderId: number, fieldsToHash?: string[]): Promise<string>;
    deleteFolder(folderId: number): Promise<BookmarkStatus>;
    addBookmarkToFolder(folderId: number, bookmarkId: number): Promise<BookmarkStatus>;
    deleteBookmarkFromFolder(folderId: number, bookmarkId: number): Promise<BookmarkStatus>;
    getFolderContentOrder(folderId: number): Promise<SimpleBookmarkOrderNode[]>;
    setFolderContentOrder(folderId: number, order: SetFolderContentOrderPayload): Promise<BookmarkStatus>;
    getFolderContent(folderId: number, layers?: number): Promise<(SimpleBookmark | SimpleBookmarkFolder)[]>;
    getFolderContentCount(folderId: number): Promise<number>;
    createFolderShare(folderId: number, shareBody: CreateFolderSharePayload): Promise<FolderShare>;
    getShare(shareId: number): Promise<FolderShare>;
    getFolderShares(folderId: number): Promise<FolderShare[]>;
    updateFolderShare(shareId: number, shareBody: UpdateFolderSharePayload): Promise<FolderShare>;
    deleteFolderShare(shareId: number): Promise<BookmarkStatus>;
    aquireClientLock(): Promise<BookmarkStatus>;
    deleteClientLock(): Promise<BookmarkStatus>;
}

// ------------------------------
//             Models
// ------------------------------


interface Note {
    /**
     * Every note has a unique identifier which is created by the server.
     * It can be used to query and update a specific note.
     * @since API version 1.0
     * @readonly
     */
    id: number;

    /**
     * The note's entity tag (ETag) indicates if a note's attribute has changed.
     * It can be used to detect if the local note has to be updated from the server.
     * @since API version 1.2
     * @readonly
     */
    etag: string;

    /**
     * Indicates if the note is read-only. This is `true` if the note is shared by another user without editing permissions.
     * If `true`, all read/write attributes become read-only, except for the `favorite` attribute.
     * @since API version 1.2
     * @readonly
     */
    readonly: boolean;

    /**
     * Notes can contain arbitrary text, formatted with Markdown. 
     * Clients should use Markdown carefully as not all markup may be supported.
     * @since API version 1.0
     */
    content: string;

    /**
     * The note's title is also used as the filename for the note's file.
     * Some special characters are removed and a sequential number is added if a note with the same title exists.
     * @since API version 1.0
     */
    title: string;

    /**
     * Every note is assigned to a category. By default, the category is an empty string (uncategorized).
     * Categories are mapped to folders, and sub-categories can be created using `/` as a delimiter.
     * @since API version 1.0
     */
    category: string;

    /**
     * If a note is marked as favorite, it is displayed at the top of the notes list. Default is `false`.
     * @since API version 1.0
     */
    favorite: boolean;

    /**
     * Unix timestamp for the last modified date/time of the note.
     * If not provided during note creation or content update, the current time is used.
     * @since API version 1.0
     */
    modified: number;
}

interface NotesSettings {
    /**
     * Path to the folder, where note's files are stored in Nextcloud.
     * The path must be relative to the user folder. Default is the localized string 'Notes'.
     * @since API version 1.2
     */
    notesPath: string;

    /**
     * Newly created note's files will have this file suffix.
     * For API version 1.2, only the values `.txt` or `.md` are allowed.
     * Since API version 1.3, custom suffixes can also be chosen. Default is `.txt`.
     * @since API version 1.2
     */
    fileSuffix: '.txt' | '.md' | string; // string to support custom suffixes from version 1.3
}



// ------------------------------
//             Requests
// ------------------------------

interface NotesSearchParams {
    /**
     * Filter the result by category name, e.g., ?category=recipes.
     * Notes with a different category are excluded from the result.
     * @since API version 1.1
     */
    category?: string;

    /**
     * Fields to be excluded from the response, separated by commas.
     * E.g., ?exclude=content,title. This reduces transferred data size.
     * @since API version 1.0
     */
    exclude?: string;

    /**
     * Only notes that haven't changed before this Unix timestamp are included in the response.
     * The result contains only the `id` attribute for such notes.
     * @since API version 1.0
     */
    pruneBefore?: number;

    /**
     * Limits the number of full notes in the response to the given number.
     * If there are more notes, the result is chunked, and a cursor is provided to fetch the next chunk.
     * @since API version 1.2
     */
    chunkSize?: number;

    /**
     * A cursor string for fetching the next chunk of notes when using chunkSize.
     * You should use the cursor value from the previous request's X-Notes-Chunk-Cursor header.
     * Don't use this parameter for the first chunk request.
     * @since API version 1.2
     */
    chunkCursor?: string;

    /**
     * HTTP header used to reduce transferred data size by providing the ETag value from the previous response.
     * The ETag is used for cache validation.
     * @since API version 1.0
     */
    'If-None-Match'?: string; // This is an HTTP header, not a query parameter, but included here for consistency
}

interface NotePayload {
    /**
     * Notes can contain arbitrary text, formatted with Markdown. 
     * Clients should use Markdown carefully as not all markup may be supported.
     * @since API version 1.0
     */
    content?: string;

    /**
     * The note's title is also used as the filename for the note's file.
     * Some special characters are removed and a sequential number is added if a note with the same title exists.
     * @since API version 1.0
     */
    title?: string;

    /**
     * Every note is assigned to a category. By default, the category is an empty string (uncategorized).
     * Categories are mapped to folders, and sub-categories can be created using `/` as a delimiter.
     * @since API version 1.0
     */
    category?: string;

    /**
     * If a note is marked as favorite, it is displayed at the top of the notes list. Default is `false`.
     * @since API version 1.0
     */
    favorite?: boolean;
}

interface NotesSettingsPayload {
    /**
     * Path to the folder, where note's files are stored in Nextcloud.
     * The path must be relative to the user folder. Default is the localized string 'Notes'.
     * @since API version 1.2
     */
    notesPath?: string;

    /**
     * Newly created note's files will have this file suffix.
     * For API version 1.2, only the values `.txt` or `.md` are allowed.
     * Since API version 1.3, custom suffixes can also be chosen. Default is `.txt`.
     * @since API version 1.2
     */
    fileSuffix?: '.txt' | '.md' | string; // string to support custom suffixes from version 1.3
}

declare class NotesClient extends BaseApiClient {
    queryNotes(query?: NotesSearchParams): Promise<Note[]>;
    getNote(noteId: number): Promise<Note>;
    createNote(payload: NotePayload): Promise<Note>;
    updateNote(noteId: number, payload: NotePayload): Promise<Note>;
    deleteNote(noteId: number): Promise<void>;
    getSettings(): Promise<NotesSettings>;
    updateSettings(payload: NotesSettingsPayload): Promise<NotesSettings>;
}

interface NextcloudInstance {
    version: Version;
    capabilities: Capabilities;
}

interface Version {
    major: number;
    minor: number;
    micro: number;
    string: string;
    edition: string;
    extendedSupport: boolean;
}

interface Capabilities {
    theming: Theming;
    [key: string]: any; // Allowing other optional capabilities
}

interface Theming {
    name: string;
    url: string;
    slogan: string;
    color: string;
    color_text: string;
    color_element: string;
    color_element_bright: string;
    color_element_dark: string;
    logo: string;
    background: string;
    background_text: string;
    background_plain: boolean;
    background_default: boolean;
    logoheader: string;
    favicon: string;
}

interface UserQuota {
    free: number;
    used: number;
    total: number;
    relative: number;
    quota: number;
  }
  
  interface BackendCapabilities {
    setDisplayName: boolean;
    setPassword: boolean;
  }
  
  interface UserInfo {
    enabled: boolean;
    id: string;
    lastLogin: number; // Representing a timestamp in milliseconds
    backend: string;
    subadmin: string[]; // Assuming it's an array of subadmin identifiers or roles
    quota: UserQuota;
    manager: string;
    avatarScope: string;
    email: string | null; // email could be null
    emailScope: string;
    additional_mail: string[]; // Array of additional email addresses
    additional_mailScope: string[]; // Scope of additional mail
    displayname: string;
    display_name: string;
    displaynameScope: string;
    phone: string;
    phoneScope: string;
    address: string;
    addressScope: string;
    website: string;
    websiteScope: string;
    twitter: string;
    twitterScope: string;
    fediverse: string;
    fediverseScope: string;
    organisation: string;
    organisationScope: string;
    role: string;
    roleScope: string;
    headline: string;
    headlineScope: string;
    biography: string;
    biographyScope: string;
    profile_enabled: string; // A string but could be a boolean depending on backend
    profile_enabledScope: string;
    groups: string[]; // Array of group names
    language: string;
    locale: string;
    notify_email: string | null; // Notify email could be null
    backendCapabilities: BackendCapabilities;
  }

  interface Status {
    status: string; // status like "offline"
    message: string | null; // message can be null
    icon: string | null; // icon can be null
    clearAt: number | null; // timestamp when the status will be cleared, or null
  }
  
  interface AutocompleteSearchResult {
    id: string; // ID of the result (e.g., "testaccount2")
    label: string; // Label of the result (e.g., "testaccount2")
    icon: string; // Icon associated with the result (e.g., "icon-user")
    source: string; // The source of the result (e.g., "users")
    status: Status; // The status information
    subline: string; // Additional information (could be empty)
    shareWithDisplayNameUnique: string; // Unique display name for sharing (e.g., "testaccount2")
  }
  
  type AutocompleteSearchResults = AutocompleteSearchResult[];

declare class GeneralClient extends BaseApiClient {
    getCapabilities(): Promise<NextcloudInstance>;
    getUserInfo(userId: string): Promise<UserInfo>;
    queryUsernames(query: string): Promise<AutocompleteSearchResults>;
}

interface AnonymousLoginResponse {
    poll:{
        token:string;
        endpoint:string;
    }
    login:string;
}

interface AnonymousLoginPollResults{
    server:string;
    loginName:string;
    appPassword:string;
}

declare class AuthClient extends BaseApiClient {
    initiateAnonymousLogin(): Promise<AnonymousLoginResponse>;
    startPolling(token: string, maxCounter?: number, waitTimeMs?: number): Promise<AnonymousLoginPollResults>;
}

export { AuthClient, BookmarkClient, DeckClient, GeneralClient, NotesClient };
