import { FetchOptions } from 'ofetch';
import { Ref, DeepReadonly } from 'vue';

type TFlagExcludedType<Base, Type> = {
    [Key in keyof Base]: Base[Key] extends Type ? never : Key;
};
type TAllowedNames<Base, Type> = TFlagExcludedType<Base, Type>[keyof Base];
type TOmitType<Base, Type> = Pick<Base, TAllowedNames<Base, Type>>;
type TModelConstructorType<T> = TOmitType<T, (...args: any[]) => any>;
declare abstract class Model {
    static primaryKey: string;
    protected $convertCase: boolean;
    protected $relations: Record<string, new () => Model>;
    $update(props: Partial<TModelConstructorType<typeof this>>): this;
}

type TOverride<T, R> = Omit<T, keyof R> & R;

interface IPagination {
    currentPage: number;
    lastPage: number;
    perPage: number;
    total: number;
}
declare abstract class ApiResponse<Data> {
    _apiResponse: boolean;
    protected data?: Data | null;
    protected pagination?: IPagination;
    abstract isPaginated(): boolean;
    constructor(data?: Data | null, pagination?: IPagination);
    getData(): Data | null | undefined;
    getPagination(): IPagination | undefined;
    hasData(): boolean;
    isDataNull(): boolean;
    hasPagination(): boolean;
}
declare class SimpleResponse<Data> extends ApiResponse<Data> {
    isPaginated(): boolean;
}
declare class PaginatedResponse<Data> extends ApiResponse<Data> {
    isPaginated(): boolean;
}

type TApiOptions = FetchOptions<'json'>;
type TMethod = (...args: any[]) => void;
type TMethods = Record<string, TMethod>;
type TSetupEndpoints<E> = TMethods extends E ? {} : E;
type TIdentifier = string | number;
interface IBaseModelApi<M> {
    fetchAll(options?: TApiOptions): Promise<ApiResponse<M[]>>;
    fetchOne(id: TIdentifier, options?: TApiOptions): Promise<ApiResponse<M>>;
    fetchMany(ids: TIdentifier[], options?: TApiOptions): Promise<ApiResponse<M[]>>;
    createOne<Request extends Partial<M>>(data: Request, options?: TApiOptions): Promise<ApiResponse<M>>;
    updateOne(id: TIdentifier, data: Partial<M>, options?: TApiOptions): Promise<ApiResponse<M>>;
    updateMany(ids: TIdentifier[], data: Partial<M>, options?: TApiOptions): Promise<ApiResponse<M[]>>;
    deleteOne(id: TIdentifier, options?: TApiOptions): Promise<ApiResponse<null>>;
    deleteMany(ids: TIdentifier[], options?: TApiOptions): Promise<ApiResponse<null>>;
}
interface ISetupContext$1<M> extends IBaseModelApi<M> {
    request<T>(url: string, options?: TApiOptions): Promise<ApiResponse<T>>;
    rawRequest<T = TResponse>(url: string, options?: TApiOptions): Promise<T>;
}
type TEndpointsContext<M, E> = E & ThisType<ISetupContext$1<M> & E>;
type TResponse = any;
type TPaginationMapper = (response: TResponse) => IPagination;
type TPaginationKeys = {
    [K in keyof IPagination]: string;
};
interface IPaginationSetup extends Partial<TPaginationKeys> {
    dataWrapper?: string;
    paginationWrapper?: string;
    mapper?: TPaginationMapper;
}
interface ISetup$2<M, E> {
    apiUrl?: (() => string) | string;
    uri?: (() => string) | string;
    trimSlashes?: boolean;
    endpoints?: TEndpointsContext<M, E>;
    pagination?: IPaginationSetup;
    options?: TApiOptions;
}
type TApi<M, E> = E & IBaseModelApi<M> & TOverride<IBaseModelApi<M>, TSetupEndpoints<E>>;
interface IApiDefinition<M, E> {
    (): TApi<M, E>;
}
declare function defineApi<M extends Model, E = {}>(ModelClass: new () => M, setup?: ISetup$2<M, E>): IApiDefinition<M, E>;

interface ISetup$1<M extends Model, Methods> {
    local?: boolean;
    methods?: Methods & ThisType<IBaseMethods<M> & Methods>;
}
interface IRepositoryDefinition<M extends Model, Methods> {
    (): TRepository<M, Methods>;
}
type TRepository<M extends Model, Methods> = IBaseMethods<M> & Methods;
interface IBaseMethods<M extends Model> {
    items: Ref<Map<string, M>>;
    isEmpty(): boolean;
    isNotEmpty(): boolean;
    count(): number;
    clear(): void;
    set(items: M[]): void;
    add(items: M[] | M): void;
    all(): M[];
    find(id: string): M | null;
    first(): M | null;
    last(): M | null;
    update(item: M, data?: Partial<M>): void;
    update(item: string, data: Partial<M>): void;
    remove(items: (M | string)[] | M | string): void;
    toArray(): M[];
    getWatchable(): Readonly<Ref<ReadonlyMap<string, DeepReadonly<M>>>>;
}
declare function defineRepository<M extends Model, Methods = {}>(ModelClass: new () => M, setup?: ISetup$1<M, Methods>): IRepositoryDefinition<M, Methods>;

interface IPaginationInstance {
    get(): IPagination | null;
    set(pagination: IPagination): void;
    clear(): void;
}

type TActionsContext<M extends Model, ApiEndpoints, CustomRepositoryMethods, CustomActions> = CustomActions & ThisType<CustomActions & ISetupContext<M, ApiEndpoints, CustomRepositoryMethods>>;
type TController<M extends Model, ApiEndpoints, RepositoryMethods, CustomActions> = IBaseController<M, ApiEndpoints, RepositoryMethods> & CustomActions & TOverride<IBaseModelApi<M>, CustomActions> & TOverride<ApiEndpoints, CustomActions>;
type TReactionsTree<ApiEndpoints> = {
    [K in keyof ApiEndpoints]-?: TReactionFunction;
};
type TReactionFunction = (response: any, ...args: any[]) => void;
interface IBaseController<M extends Model, ApiEndpoints, RepositoryMethods> {
    api: TApi<M, ApiEndpoints>;
    repository: TRepository<M, RepositoryMethods>;
    pagination: IPaginationInstance;
}
interface ISetupContext<M extends Model, ApiEndpoints, CustomRepositoryMethods> {
    api: TApi<M, ApiEndpoints>;
    repository: TRepository<M, CustomRepositoryMethods>;
}
interface ISetup<M extends Model, ApiEndpoints, RepositoryMethods, CustomActions, Reactions> {
    actions?: TActionsContext<M, ApiEndpoints, RepositoryMethods, CustomActions>;
    reactions?: Reactions;
    api?: ISetup$2<M, ApiEndpoints>;
    repository?: ISetup$1<M, RepositoryMethods>;
}
interface IControllerDefinition<M extends Model, ApiEndpoints, RepositoryMethods, CustomActions> {
    (): TController<M, ApiEndpoints, RepositoryMethods, CustomActions>;
}
declare function defineController<M extends Model, Reactions extends TReactionsTree<CustomApiEndpoints>, CustomApiEndpoints = {}, CustomRepositoryMethods = {}, CustomActions = {}>(ModelClass: new () => M, setup?: ISetup<M, CustomApiEndpoints, CustomRepositoryMethods, CustomActions, Reactions>): IControllerDefinition<M, CustomApiEndpoints, CustomRepositoryMethods, CustomActions>;
declare function defineController<M extends Model, Reactions extends TReactionsTree<CustomApiEndpoints>, CustomApiEndpoints = {}, CustomRepositoryMethods = {}, CustomActions = {}>(ModelClass: new () => M, apiDefinition: IApiDefinition<M, CustomApiEndpoints>, setup?: ISetup<M, CustomApiEndpoints, CustomRepositoryMethods, CustomActions, Reactions>): IControllerDefinition<M, CustomApiEndpoints, CustomRepositoryMethods, CustomActions>;
declare function defineController<M extends Model, Reactions extends TReactionsTree<CustomApiEndpoints>, CustomApiEndpoints = {}, CustomRepositoryMethods = {}, CustomActions = {}>(ModelClass: new () => M, repositoryDefinition: IRepositoryDefinition<M, CustomRepositoryMethods>, setup?: ISetup<M, CustomApiEndpoints, CustomRepositoryMethods, CustomActions, Reactions>): IControllerDefinition<M, CustomApiEndpoints, CustomRepositoryMethods, CustomActions>;
declare function defineController<M extends Model, Reactions extends TReactionsTree<CustomApiEndpoints>, CustomApiEndpoints = {}, CustomRepositoryMethods = {}, CustomActions = {}>(ModelClass: new () => M, apiDefinition: IApiDefinition<M, CustomApiEndpoints>, repositoryDefinition: IRepositoryDefinition<M, CustomRepositoryMethods>, setup?: ISetup<M, CustomApiEndpoints, CustomRepositoryMethods, CustomActions, Reactions>): IControllerDefinition<M, CustomApiEndpoints, CustomRepositoryMethods, CustomActions>;

type THeaders = HeadersInit | (() => HeadersInit);
interface IConfigOptions {
    apiUrl?: string;
    headers?: THeaders;
    convertCase?: boolean;
    pagination?: IPaginationSetup;
    requestOptions?: TApiOptions;
}
declare function defineConfig(options: IConfigOptions): void;

declare function createInstance<T extends Model, D extends TModelConstructorType<T>>(ModelClass: new () => T, data?: Partial<D>): T;

export { ApiResponse, type IPagination, Model, PaginatedResponse, SimpleResponse, createInstance, defineApi, defineConfig, defineController, defineRepository };
