import type { IncomingMessage, ServerResponse } from "http";
import type { RequestOptions } from "https";

import { Editor } from "tinymce";
export type DSQL_DatabaseFullName = string;

export interface DSQL_DatabaseSchemaType {
    dbName: string;
    dbSlug: string;
    dbFullName: string;
    dbDescription?: string;
    dbImage?: string;
    tables: DSQL_TableSchemaType[];
    childrenDatabases?: DSQL_ChildrenDatabaseObject[];
    childDatabase?: boolean;
    childDatabaseDbFullName?: string;
    updateData?: boolean;
}

export interface DSQL_ChildrenDatabaseObject {
    dbFullName: string;
}

export interface DSQL_TableSchemaType {
    tableName: string;
    tableFullName: string;
    tableDescription?: string;
    fields: DSQL_FieldSchemaType[];
    indexes?: DSQL_IndexSchemaType[];
    childrenTables?: DSQL_ChildrenTablesType[];
    childTable?: boolean;
    updateData?: boolean;
    childTableName?: string;
    childTableDbFullName?: string;
    tableNameOld?: string;
}

export interface DSQL_ChildrenTablesType {
    dbNameFull: string;
    tableName: string;
    tableNameFull?: string;
}

export const TextFieldTypesArray = [
    { title: "Plain Text", value: "plain" },
    { title: "Rich Text", value: "richText" },
    { title: "JSON", value: "json" },
    { title: "YAML", value: "yaml" },
    { title: "HTML", value: "html" },
    { title: "CSS", value: "css" },
    { title: "Javascript", value: "javascript" },
    { title: "Shell", value: "shell" },
] as const;

export type DSQL_FieldSchemaType = {
    fieldName?: string;
    originName?: string;
    updatedField?: boolean;
    dataType?: string;
    nullValue?: boolean;
    notNullValue?: boolean;
    primaryKey?: boolean;
    encrypted?: boolean;
    autoIncrement?: boolean;
    defaultValue?: string | number;
    defaultValueLiteral?: string;
    foreignKey?: DSQL_ForeignKeyType;
    newTempField?: boolean;
    defaultField?: boolean;
    plainText?: boolean;
    unique?: boolean;
    pattern?: string;
    patternFlags?: string;
    onUpdate?: string;
    onUpdateLiteral?: string;
    onDelete?: string;
    onDeleteLiteral?: string;
    cssFiles?: string[];
    integerLength?: string | number;
    decimals?: string | number;
} & {
    [key in (typeof TextFieldTypesArray)[number]["value"]]?: boolean;
};

export interface DSQL_ForeignKeyType {
    foreignKeyName?: string;
    destinationTableName?: string;
    destinationTableColumnName?: string;
    destinationTableColumnType?: string;
    cascadeDelete?: boolean;
    cascadeUpdate?: boolean;
}

export interface DSQL_IndexSchemaType {
    indexName?: string;
    indexType?: string;
    indexTableFields?: DSQL_IndexTableFieldType[];
    alias?: string;
    newTempIndex?: boolean;
}

export interface DSQL_IndexTableFieldType {
    value: string;
    dataType: string;
}

export interface DSQL_MYSQL_SHOW_INDEXES_Type {
    Key_name: string;
    Table: string;
    Column_name: string;
    Collation: string;
    Index_type: string;
    Cardinality: string;
    Index_comment: string;
    Comment: string;
}

export interface DSQL_MYSQL_SHOW_COLUMNS_Type {
    Field: string;
    Type: string;
    Null: string;
    Key: string;
    Default: string;
    Extra: string;
}

export interface DSQL_MYSQL_FOREIGN_KEYS_Type {
    CONSTRAINT_NAME: string;
    CONSTRAINT_SCHEMA: string;
    TABLE_NAME: string;
}

export interface DSQL_MYSQL_user_databases_Type {
    id: number;
    user_id: number;
    db_full_name: string;
    db_name: string;
    db_slug: string;
    db_image: string;
    db_description: string;
    active_clone: number;
    active_data: 0 | 1;
    active_clone_parent_db: string;
    remote_connected?: number;
    remote_db_full_name?: string;
    remote_connection_host?: string;
    remote_connection_key?: string;
    remote_connection_type?: string;
    user_priviledge?: string;
    date_created?: string;
    image_thumbnail?: string;
    first_name?: string;
    last_name?: string;
    email?: string;
}

export interface PackageUserLoginRequestBody {
    encryptionKey: string;
    payload: any;
    database: string;
    additionalFields?: string[];
    email_login?: boolean;
    email_login_code?: string;
    email_login_field?: string;
    token?: boolean;
    social?: boolean;
    dbSchema?: DSQL_DatabaseSchemaType;
    skipPassword?: boolean;
    dbUserId: string | number;
}

export interface PackageUserLoginLocalBody {
    payload: any;
    additionalFields?: string[];
    email_login?: boolean;
    email_login_code?: string;
    email_login_field?: string;
    token?: boolean;
    social?: boolean;
    dbSchema?: DSQL_DatabaseSchemaType;
    skipPassword?: boolean;
}

export type ImageInputFileToBase64FunctionReturn = {
    imageBase64?: string;
    imageBase64Full?: string;
    imageName?: string;
    imageSize?: number;
};

export interface GetReqQueryObject {
    db: string;
    query: string;
    queryValues?: string;
    tableName?: string;
    debug?: boolean;
}

export type DATASQUIREL_LoggedInUser = {
    id: number;
    uuid?: string;
    first_name: string;
    last_name: string;
    email: string;
    phone?: string;
    user_type?: string;
    username?: string;
    image?: string;
    image_thumbnail?: string;
    social_login?: number;
    social_platform?: string;
    social_id?: string;
    verification_status?: number;
    csrf_k: string;
    logged_in_status: boolean;
    date: number;
} & {
    [key: string]: any;
};

export interface AuthenticatedUser {
    success: boolean;
    payload: DATASQUIREL_LoggedInUser | null;
    msg?: string;
    userId?: number;
    cookieNames?: any;
}

export interface SuccessUserObject {
    id: number;
    first_name: string;
    last_name: string;
    email: string;
}

export interface AddUserFunctionReturn {
    success: boolean;
    payload?: SuccessUserObject | null;
    msg?: string;
    sqlResult?: any;
}

export interface GoogleIdentityPromptNotification {
    getMomentType: () => string;
    getDismissedReason: () => string;
    getNotDisplayedReason: () => string;
    getSkippedReason: () => string;
    isDismissedMoment: () => boolean;
    isDisplayMoment: () => boolean;
    isDisplayed: () => boolean;
    isNotDisplayed: () => boolean;
    isSkippedMoment: () => boolean;
}

export type UserDataPayload = {
    first_name: string;
    last_name: string;
    email: string;
    password?: string;
    username?: string;
} & {
    [key: string]: any;
};

export interface GetUserFunctionReturn {
    success: boolean;
    payload: {
        id: number;
        first_name: string;
        last_name: string;
        username: string;
        email: string;
        phone: string;
        social_id: [string];
        image: string;
        image_thumbnail: string;
        verification_status: [number];
    } | null;
}

export interface ReauthUserFunctionReturn {
    success: boolean;
    payload: DATASQUIREL_LoggedInUser | null;
    msg?: string;
    userId?: number;
    token?: string;
}

export interface UpdateUserFunctionReturn {
    success: boolean;
    payload?: Object[] | string;
}

export interface GetReturn {
    success: boolean;
    payload?: any;
    msg?: string;
    error?: string;
    schema?: DSQL_TableSchemaType;
    finalQuery?: string;
}

export interface GetSchemaRequestQuery {
    database?: string;
    table?: string;
    field?: string;
    user_id?: string | number;
}

export interface GetSchemaAPICredentialsParam {
    key: string;
}

export type GetSchemaAPIParam = GetSchemaRequestQuery &
    GetSchemaAPICredentialsParam;

export interface PostReturn {
    success: boolean;
    payload?: Object[] | string | PostInsertReturn;
    msg?: string;
    error?: any;
    schema?: DSQL_TableSchemaType;
}

export interface PostDataPayload {
    action: "insert" | "update" | "delete";
    table: string;
    data?: object;
    identifierColumnName?: string;
    identifierValue?: string;
    duplicateColumnName?: string;
    duplicateColumnValue?: string;
    update?: boolean;
}

export interface LocalPostReturn {
    success: boolean;
    payload?: any;
    msg?: string;
    error?: string;
}

export interface LocalPostQueryObject {
    query: string | PostDataPayload;
    tableName?: string;
    queryValues?: string[];
}

export interface PostInsertReturn {
    fieldCount: number;
    affectedRows: number;
    insertId: number;
    serverStatus: number;
    warningCount: number;
    message: string;
    protocol41: boolean;
    changedRows: number;
}

export type UserType = DATASQUIREL_LoggedInUser;

export interface ApiKeyDef {
    name: string;
    scope: string;
    date_created: string;
    apiKeyPayload: string;
}

export interface MetricsType {
    dbCount: number;
    tablesCount: number;
    mediaCount: number;
    apiKeysCount: number;
}

export interface DashboardContextType {
    user?: UserType;
    databases?: DSQL_MYSQL_user_databases_Type[];
    setTargetDatabase?: React.Dispatch<
        React.SetStateAction<DSQL_MYSQL_user_databases_Type | undefined>
    >;
    targetDatabase?: DSQL_MYSQL_user_databases_Type;
    metrics?: MetricsType;
}

export interface AddDbContextType {
    user?: UserType;
    databases?: DSQL_MYSQL_user_databases_Type[];
    dbImage?: string | null | ImageObjectType;
    setDbImage?: React.Dispatch<
        React.SetStateAction<string | null | ImageObjectType>
    >;
    query?: any;
    duplicateDb?: DSQL_MYSQL_user_databases_Type;
}

export interface EditDbContextType {
    user?: UserType;
    database?: DSQL_MYSQL_user_databases_Type;
    dbImage?: string | null | ImageObjectType;
    setDbImage?: React.Dispatch<
        React.SetStateAction<string | null | ImageObjectType>
    >;
}

export interface RichTextEditorsRefArray {
    fieldName: string;
    ref: React.MutableRefObject<Editor>;
}

export interface JSONTextEditorsRefArray {
    fieldName: string;
    ref: React.MutableRefObject<AceAjax.Editor>;
}

export interface TableEntriesContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    table: DSQL_TableSchemaType;
    dbSchemaData: DSQL_DatabaseSchemaType[];
    entries: any[];
    targetEntry?: any;
    setTargetEntry: React.Dispatch<React.SetStateAction<any>>;
    richTextEditors: React.MutableRefObject<RichTextEditorsRefArray[]>;
    jsonTextEditors: React.MutableRefObject<JSONTextEditorsRefArray[]>;
    query?: any;
    confirmedDelegetedUser?: any;
    activeEntries: any[] | null;
    setActiveEntries: React.Dispatch<React.SetStateAction<any[] | null>>;
    targetField: React.MutableRefObject<string>;
    searchTerm: React.MutableRefObject<string | null>;
    entriesCount: number;
}

export interface AddEntryContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    table: DSQL_TableSchemaType;
    dbSchemaData: DSQL_DatabaseSchemaType[];
    richTextEditors: React.MutableRefObject<RichTextEditorsRefArray[]>;
    jsonTextEditors: React.MutableRefObject<JSONTextEditorsRefArray[]>;
    query: any;
    duplicateEntry: any;
    confirmedDelegetedUser: any;
}

export interface UserDatabasesContextType {
    user: UserType;
    users: any[];
    targetUser: any;
    setTargetUser: React.Dispatch<React.SetStateAction<any>>;
    databases: DSQL_MYSQL_user_databases_Type[];
}

export interface SettingsPageContextType {
    user: UserType;
    image: any;
    setImage: React.Dispatch<React.SetStateAction<any>>;
    activeUser: any;
}

export interface MediaFolderPageContextType {
    user: UserType;
    media: any[];
    targetMedia: any;
    setTargetMedia: React.Dispatch<React.SetStateAction<any>>;
    folders: any[];
    query: any;
    staticHost: string;
    folder: string;
}

export interface TablesContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    tables: MYSQL_user_database_tables_table_def[];
    targetTable: MYSQL_user_database_tables_table_def | null;
    setTargetTable: React.Dispatch<
        React.SetStateAction<MYSQL_user_database_tables_table_def | null>
    >;
    query: any;
    confirmedDelegetedUser: any;
}

export interface EditTableContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    table: DSQL_TableSchemaType;
    tableFields: DSQL_FieldSchemaType[];
    setTableFields: React.Dispatch<
        React.SetStateAction<DSQL_FieldSchemaType[]>
    >;
    targetField: DSQL_FieldSchemaType | null;
    setTargetField: React.Dispatch<
        React.SetStateAction<DSQL_FieldSchemaType | null>
    >;
    pageRefresh: number;
    setPageRefresh: React.Dispatch<React.SetStateAction<number>>;
    refreshFieldsListRef: React.MutableRefObject<
        React.Dispatch<React.SetStateAction<number>> | undefined
    >;
    dbSchemaData: DSQL_DatabaseSchemaType[];
    query: any;
    confirmedDelegetedUser: any;
}

export interface SingleDatabaseContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    tables: MYSQL_user_database_tables_table_def[];
    targetTable: MYSQL_user_database_tables_table_def | null;
    setTargetTable: React.Dispatch<
        React.SetStateAction<MYSQL_user_database_tables_table_def | null>
    >;
    query: any;
    confirmedDelegetedUser: any;
}

export interface ApiKeysContextType {
    user?: UserType;
    apiKeys?: any[];
    setApiKeys?: React.Dispatch<React.SetStateAction<any[]>>;
    targetApiKey?: any | null;
    setTargetApiKey?: React.Dispatch<React.SetStateAction<any | null>>;
    newApiKey?: any | null;
    setNewApiKey?: React.Dispatch<React.SetStateAction<any | null>>;
}

export interface LoginFormContextType {
    user?: UserType | null;
    loading: boolean;
    setLoading: React.Dispatch<React.SetStateAction<boolean>>;
    alert: string | boolean;
    setAlert: React.Dispatch<React.SetStateAction<string | boolean>>;
}

export interface CreateAccountContextType {
    user?: UserType | null;
    query: CreateAccountQueryType;
    invitingUser: any;
}

export interface CreateAccountQueryType {
    invite?: number;
    database_access?: string;
    priviledge?: string;
    email?: string;
}

export interface DocsAsidePageObject {
    id: number;
    title: string;
    slug: string;
    parent_id?: number;
    level?: number;
}

export interface AllUserUsersContextType {
    user?: UserType;
    users?: MYSQL_delegated_users_table_def[];
    targetUser?: MYSQL_user_users_table_def | undefined;
    setTargetUser?: React.Dispatch<
        React.SetStateAction<MYSQL_user_users_table_def | undefined>
    >;
    databases?: DSQL_MYSQL_user_databases_Type[];
    pendingInvitations?: MYSQL_invitations_table_def[];
    pendingInvitationsReceived?: any[];
    adminUsers?: any[];
    invitedAccounts?: any[];
}

export interface AddSocialLoginContextType {
    user?: UserType;
    database?: DSQL_MYSQL_user_databases_Type;
    query?: any;
    socialLogins?: SocialLoginObjectType[];
}

export interface DelegatedDbContextType {
    user: UserType;
    users: MYSQL_user_users_table_def[];
    targetUser: MYSQL_user_users_table_def | undefined;
    setTargetUser: React.Dispatch<
        React.SetStateAction<MYSQL_user_users_table_def | undefined>
    >;
    database: DSQL_MYSQL_user_databases_Type;
}

export interface AddUserUserContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    table: DSQL_TableSchemaType;
    query: any;
    confirmedDelegetedUser: any;
}

export interface UserUsersContextType {
    user: UserType;
    users: MYSQL_user_users_table_def[];
    targetUser?: MYSQL_user_users_table_def;
    setTargetUser: React.Dispatch<
        React.SetStateAction<MYSQL_user_users_table_def | undefined>
    >;
    database: DSQL_MYSQL_user_databases_Type;
    table: DSQL_TableSchemaType;
    dbSchemaData: DSQL_DatabaseSchemaType[];
    query: any;
    confirmedDelegetedUser: any;
}

export interface DatabaseSingleUserContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    singleUser: MYSQL_user_users_table_def;
    table: DSQL_TableSchemaType;
    dbSchemaData: DSQL_DatabaseSchemaType[];
    query: any;
    confirmedDelegetedUser: any;
}

export interface SingleUserUserContextType {
    user: UserType;
    singleUser: MYSQL_user_users_table_def;
}

export interface AddUserContextType {
    user: UserType;
    users: MYSQL_delegated_users_table_def[];
    databases: DSQL_MYSQL_user_databases_Type[];
    query: any;
}

export interface MediaContextType {
    user: UserType;
    media: MYSQL_user_media_table_def[];
    targetMedia: MYSQL_user_media_table_def | null;
    setTargetMedia: React.Dispatch<
        React.SetStateAction<MYSQL_user_media_table_def | null>
    >;
    folders: string[];
    staticHost: string;
}

export interface MediaSubFolderContextType {
    user: UserType;
    media: MYSQL_user_media_table_def[];
    targetMedia: MYSQL_user_media_table_def | null;
    setTargetMedia: React.Dispatch<
        React.SetStateAction<MYSQL_user_media_table_def | null>
    >;
    folders: string[];
    query: any;
    folder: string;
    staticHost: string;
}

export interface FieldsContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    table: DSQL_TableSchemaType;
    dbSchemaData: DSQL_DatabaseSchemaType[];
    targetField: DSQL_FieldSchemaType | null;
    setTargetField: React.Dispatch<
        React.SetStateAction<DSQL_FieldSchemaType | null>
    >;
    refreshFieldsListRef: React.MutableRefObject<
        React.Dispatch<React.SetStateAction<number>> | undefined
    >;
    tableFields: DSQL_FieldSchemaType[];
    setTableFields: React.Dispatch<
        React.SetStateAction<DSQL_FieldSchemaType[]>
    >;
    updateTableAfterFieldsUpdateFunction: () => void;
    query: any;
    confirmedDelegetedUser: any;
}

export interface SingleTableContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    table: DSQL_TableSchemaType;
    tableRecord: MYSQL_user_database_tables_table_def;
    tableFields: DSQL_FieldSchemaType[];
    setTableFields: React.Dispatch<
        React.SetStateAction<DSQL_FieldSchemaType[]>
    >;
    tableIndexes: DSQL_IndexSchemaType[];
    setTableIndexes: React.Dispatch<
        React.SetStateAction<DSQL_IndexSchemaType[]>
    >;
    dbSchemaData: DSQL_DatabaseSchemaType[];
    entries: any[];
    targetEntry: any;
    setTargetEntry: React.Dispatch<React.SetStateAction<any>>;
    richTextEditors: React.MutableRefObject<RichTextEditorsRefArray[]>;
    jsonTextEditors: React.MutableRefObject<JSONTextEditorsRefArray[]>;
    query: any;
    confirmedDelegetedUser: any;
    targetField: DSQL_FieldSchemaType | null;
    setTargetField: React.Dispatch<
        React.SetStateAction<DSQL_FieldSchemaType | null>
    >;
    refreshFieldsListRef: React.MutableRefObject<
        React.Dispatch<React.SetStateAction<number>>
    >;
    updateTableAfterFieldsUpdateFunction: () => void;
    entriesCount: number;
}

export interface SingleEntryContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    table: DSQL_TableSchemaType;
    dbSchemaData: DSQL_DatabaseSchemaType[];
    entry: any;
    targetEntry: any;
    setTargetEntry: React.Dispatch<React.SetStateAction<any>>;
    richTextEditors: React.MutableRefObject<RichTextEditorsRefArray[]>;
    jsonTextEditors: React.MutableRefObject<JSONTextEditorsRefArray[]>;
    query: any;
    confirmedDelegetedUser: any;
    prevEntry: any;
    nextEntry: any;
}

export interface UserSchemaContextType {
    user: UserType;
    dbSchemaData: DSQL_DatabaseSchemaType[];
}

export interface ConnectContextType {
    user?: UserType;
    query?: any;
    mariadbUserCred?: MariaDBUserCredType;
    mariadbUsers?: MYSQL_mariadb_users_table_def[];
    targetMariadbUser?: MYSQL_mariadb_users_table_def | null;
    setTargetMariadbUser?: React.Dispatch<
        React.SetStateAction<MYSQL_mariadb_users_table_def | null>
    >;
    refresh?: number;
    setRefresh?: React.Dispatch<React.SetStateAction<number>>;
}

export interface MYSQL_mariadb_users_table_def {
    id?: number;
    user_id?: number;
    username?: string;
    host?: string;
    password?: string;
    primary?: number;
    grants?: string;
    date_created?: string;
    date_created_code?: number;
    date_created_timestamp?: string;
    date_updated?: string;
    date_updated_code?: number;
    date_updated_timestamp?: string;
}

export interface DbContextType {
    user?: UserType;
    databases?: DSQL_MYSQL_user_databases_Type[];
    targetDatabase?: DSQL_MYSQL_user_databases_Type;
    setTargetDatabase?: React.Dispatch<
        React.SetStateAction<DSQL_MYSQL_user_databases_Type | undefined>
    >;
}

export interface MariaDBUserCredType {
    mariadb_user?: string;
    mariadb_host?: string;
    mariadb_pass?: string;
}

export interface AddTableContextType {
    user?: UserType;
    dbSchemaData?: DSQL_DatabaseSchemaType[];
    database?: DSQL_MYSQL_user_databases_Type;
    tables?: DSQL_TableSchemaType[];
    tableFields?: DSQL_FieldSchemaType[];
    setTableFields?: React.Dispatch<
        React.SetStateAction<DSQL_FieldSchemaType[]>
    >;
    targetField?: DSQL_FieldSchemaType | null;
    setTargetField?: React.Dispatch<
        React.SetStateAction<DSQL_FieldSchemaType | null>
    >;
    pageRefresh?: number | null;
    setPageRefresh?: React.Dispatch<React.SetStateAction<number>>;
    refreshFieldsListRef?: React.MutableRefObject<
        React.Dispatch<React.SetStateAction<number>> | undefined
    >;
    query?: any;
}

export interface DbSchemaContextType {
    user?: UserType;
    database?: DSQL_MYSQL_user_databases_Type;
    dbImage?: string;
    setDbImage?: React.Dispatch<React.SetStateAction<string>>;
    dbSchemaData?: DSQL_DatabaseSchemaType[];
    tables?: any[];
}

export interface DbShellContextType {
    user?: UserType;
    database?: DSQL_MYSQL_user_databases_Type;
    dbImage?: string;
    setDbImage?: React.Dispatch<React.SetStateAction<string>>;
    dbSchemaData?: DSQL_DatabaseSchemaType[];
    tables?: any[];
}

export interface DbConnectContextType {
    user: UserType;
    database: DSQL_MYSQL_user_databases_Type;
    targetDbSchema: DSQL_DatabaseSchemaType;
    query: any;
}

export interface ImageObjectType {
    imageName?: string;
    mimeType?: string;
    imageSize?: number;
    private?: boolean;
    imageBase64?: string;
    imageBase64Full?: string;
}

export interface FileObjectType {
    fileName?: string;
    private?: boolean;
    fileType?: string;
    fileSize?: number;
    fileBase64?: string;
    fileBase64Full?: string;
}

export interface SocialLoginObjectType {
    platform?: string;
    paradigm?: string;
    clientId?: string;
    clientSecret?: string;
    callbackUrl?: string;
    domain1?: string;
    domain2?: string;
    domain3?: string;
}

export interface DbConnectType {
    url: string;
    key: string;
    database: DSQL_MYSQL_user_databases_Type;
    dbSchema: DSQL_DatabaseSchemaType;
    type: "pull" | "push";
    remoteDbs?: DSQL_DatabaseSchemaType[];
    targetDb?: DSQL_DatabaseSchemaType;
}

export interface MYSQL_MediaType {
    id?: number;
    user_id?: number;
    media_name?: string;
    folder?: string;
    media_url?: string;
    media_thumbnail_url?: string;
    media_type?: string;
    width?: string;
    height?: string;
    size?: string;
    private?: string;
}

export interface UserFileObject {
    title?: string;
    path?: string;
    data?: string;
}

export interface UserFileObject2 {
    type?: string;
    name?: string;
    root?: string;
    content?: UserFileObject2[];
}

export interface MYSQL_user_users_table_def {
    id?: number;
    user_id?: number;
    invited_user_id?: number;
    database?: string;
    database_access?: string;
    first_name?: string;
    last_name?: string;
    email?: string;
    username?: string;
    password?: string;
    phone?: string;
    user_type?: string;
    user_priviledge?: string;
    image?: string;
    image_thumbnail?: string;
    city?: string;
    state?: string;
    country?: string;
    zip_code?: string;
    address?: string;
    social_login?: number;
    social_platform?: string;
    social_id?: string;
    verification_status?: number;
    more_user_data?: string;
    date_created?: string;
    date_created_code?: number;
    date_created_timestamp?: string;
    date_updated?: string;
    date_updated_code?: number;
    date_updated_timestamp?: string;
    inviteeFirstName?: string;
    inviteeLastName?: string;
    inviteeEmail?: string;
    inviteeImage?: string;
}

export interface MYSQL_user_database_tables_table_def {
    id?: number;
    user_id?: number;
    db_id?: number;
    db_slug?: string;
    table_name?: string;
    table_slug?: string;
    table_description?: string;
    child_table?: number;
    active_data?: 0 | 1;
    child_table_parent_database?: string;
    child_table_parent_table?: string;
    date_created?: string;
    date_created_code?: number;
    date_created_timestamp?: string;
    date_updated?: string;
    date_updated_code?: number;
    date_updated_timestamp?: string;
}

export interface MYSQL_user_media_table_def {
    id?: number;
    user_id?: number;
    media_name?: string;
    folder?: string;
    media_url?: string;
    media_thumbnail_url?: string;
    media_path?: string;
    media_thumbnail_path?: string;
    media_type?: string;
    width?: number;
    height?: number;
    size?: number;
    private?: number;
    date_created?: string;
    date_created_code?: number;
    date_created_timestamp?: string;
    date_updated?: string;
    date_updated_code?: number;
    date_updated_timestamp?: string;
}

export interface MYSQL_delegated_users_table_def {
    id?: number;
    user_id?: number;
    delegated_user_id?: number;
    permissions?: string;
    permission_level_code?: number;
    date_created?: string;
    date_created_code?: number;
    date_created_timestamp?: string;
    date_updated?: string;
    date_updated_code?: number;
    date_updated_timestamp?: string;
}

export interface MYSQL_invitations_table_def {
    id?: number;
    inviting_user_id?: number;
    invited_user_email?: string;
    invitation_status?: string;
    database_access?: string;
    priviledge?: string;
    db_tables_data?: string;
    date_created?: string;
    date_created_code?: number;
    date_created_timestamp?: string;
    date_updated?: string;
    date_updated_code?: number;
    date_updated_timestamp?: string;
}

export interface MYSQL_docs_pages_table_def {
    id?: number;
    title?: string;
    slug?: string;
    description?: string;
    content?: string;
    text_content?: string;
    level?: number;
    page_order?: number;
    parent_id?: number;
    date_created?: string;
    date_created_code?: number;
    date_created_timestamp?: string;
    date_updated?: string;
    date_updated_code?: number;
    date_updated_timestamp?: string;
}

export interface MYSQL_delegated_user_tables_table_def {
    id?: number;
    delegated_user_id?: number;
    root_user_id?: number;
    database?: string;
    table?: string;
    priviledge?: string;
    date_created?: string;
    date_created_code?: number;
    date_created_timestamp?: string;
    date_updated?: string;
    date_updated_code?: number;
    date_updated_timestamp?: string;
}

export type ApiKeyObject = {
    user_id?: string | number;
    full_access?: boolean;
    sign?: string;
    date_code?: number;
    target_database?: string;
    target_table?: string;
    error?: string;
};

export type AddApiKeyRequestBody = {
    api_key_name: string;
    api_key_slug: string;
    api_key_scope?: "fullAccess" | "readOnly";
    target_database?: string;
    target_table?: string;
};

export type CheckApiCredentialsFn = (
    param: CheckApiCredentialsFnParam
) => ApiKeyObject | null | undefined;
export type CheckApiCredentialsFnParam = {
    key?: string;
    database?: string;
    table?: string;
    user_id?: string | number;
    media?: boolean;
};

export type FetchApiFn = (
    url: string,
    options?: FetchApiOptions,
    csrf?: boolean
) => Promise<any>;

export type FetchApiOptions = RequestInit & {
    method:
        | "POST"
        | "GET"
        | "DELETE"
        | "PUT"
        | "PATCH"
        | "post"
        | "get"
        | "delete"
        | "put"
        | "patch";
    body?: object | string;
    headers?: FetchHeader;
    query?: { [key: string]: any };
};

type FetchHeader = HeadersInit & {
    [key: string]: any;
};

export type FetchApiReturn = {
    success: boolean;
    payload: any;
    msg?: string;
    [key: string]: any;
};

export const ServerQueryOperators = ["AND", "OR"] as const;
export const ServerQueryEqualities = ["EQUAL", "LIKE", "NOT EQUAL"] as const;

export type ServerQueryParam<
    T extends { [k: string]: any } = { [k: string]: any }
> = {
    selectFields?: string[];
    query?: ServerQueryQueryObject<T>;
    limit?: number;
    page?: number;
    offset?: number;
    order?: {
        field: keyof T;
        strategy: "ASC" | "DESC";
    };
    searchOperator?: (typeof ServerQueryOperators)[number];
    searchEquality?: (typeof ServerQueryEqualities)[number];
    addUserId?: {
        fieldName: keyof T;
    };
    join?: ServerQueryParamsJoin[];
    [key: string]: any;
};

export type ServerQueryObject<T extends object = { [key: string]: any }> = {
    value?: string | string[];
    operator?: (typeof ServerQueryOperators)[number];
    equality?: (typeof ServerQueryEqualities)[number];
    tableName?: string;
    __query?: {
        [key in keyof T]: Omit<ServerQueryObject<T>, "__query">;
    };
};

export type ServerQueryQueryObject<T extends object = { [key: string]: any }> =
    {
        [key in keyof T]: ServerQueryObject<T>;
    };

export type FetchDataParams = {
    path: string;
    method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
    body?: object | string;
    query?: AuthFetchQuery;
    tableName?: string;
};

export type AuthFetchQuery = ServerQueryParam & {
    [key: string]: any;
};

export type ServerQueryParamsJoin<
    Table extends string = string,
    Field extends object = { [key: string]: any }
> = {
    joinType: "INNER JOIN" | "JOIN" | "LEFT JOIN" | "RIGHT JOIN";
    alias?: string;
    tableName: Table;
    match?:
        | ServerQueryParamsJoinMatchObject<Field>
        | ServerQueryParamsJoinMatchObject<Field>[];
    selectFields?: (
        | keyof Field
        | {
              field: keyof Field;
              alias?: string;
              count?: boolean;
          }
    )[];
    operator?: (typeof ServerQueryOperators)[number];
};

export type ServerQueryParamsJoinMatchObject<
    Field extends object = { [key: string]: any }
> = {
    /** Field name from the **Root Table** */
    source: string | ServerQueryParamsJoinMatchSourceTargetObject;
    /** Field name from the **Join Table** */
    target?: keyof Field | ServerQueryParamsJoinMatchSourceTargetObject;
    /** A literal value: No source and target Needed! */
    targetLiteral?: string;
};

export type ServerQueryParamsJoinMatchSourceTargetObject = {
    tableName: string;
    fieldName: string;
};

export type ApiConnectBody = {
    url: string;
    key: string;
    database: DSQL_MYSQL_user_databases_Type;
    dbSchema: DSQL_DatabaseSchemaType;
    type: "pull" | "push";
    user_id?: string | number;
};

export type SuUserType = {
    email: string;
    password: string;
    authKey: string;
    logged_in_status: boolean;
    date: number;
};

export type MariadbRemoteServerObject = {
    host: string;
    port: number;
    primary?: boolean;
    loadBalanced?: boolean;
    users?: MariadbRemoteServerUserObject[];
};

export type MariadbRemoteServerUserObject = {
    name: string;
    password: string;
    host: string;
};

export type APILoginFunctionParams = {
    encryptionKey: string;
    email: string;
    username?: string;
    password?: string;
    database: string;
    additionalFields?: string[];
    email_login?: boolean;
    email_login_code?: string;
    email_login_field?: string;
    token?: boolean;
    skipPassword?: boolean;
    social?: boolean;
    dbUserId?: number | string;
    debug?: boolean;
};
export type APILoginFunctionReturn = {
    success: boolean;
    msg?: string;
    payload?: DATASQUIREL_LoggedInUser | null;
    userId?: number | string;
    key?: string;
    token?: string;
    csrf?: string;
    cookieNames?: any;
};

export type APICreateUserFunctionParams = {
    encryptionKey?: string;
    payload: any;
    database: string;
    userId?: string | number;
};

export type APICreateUserFunction = (
    params: APICreateUserFunctionParams
) => Promise<AddUserFunctionReturn>;

/**
 * API Get User Function
 */
export type APIGetUserFunctionParams = {
    fields: string[];
    dbFullName: string;
    userId: string | number;
};

/**
 * API Google Login Function
 */
export type APIGoogleLoginFunctionParams = {
    token: string;
    database?: string;
    additionalFields?: string[];
    additionalData?: { [key: string]: string | number };
    debug?: boolean;
};

export type APIGoogleLoginFunction = (
    params: APIGoogleLoginFunctionParams
) => Promise<APILoginFunctionReturn>;

/**
 * Handle Social DB Function
 */
export type HandleSocialDbFunctionParams = {
    database?: string;
    social_id: string | number;
    email: string;
    social_platform: string;
    payload: any;
    invitation?: any;
    supEmail?: string;
    additionalFields?: string[];
    debug?: boolean;
};

export type HandleSocialDbFunctionReturn = {
    success: boolean;
    user?: DATASQUIREL_LoggedInUser | null;
    msg?: string;
    social_id?: string | number;
    social_platform?: string;
    payload?: any;
    alert?: boolean;
    newUser?: any;
    error?: any;
} | null;

/**
 * Handle Social User Auth on Datasquirel Database
 * ==============================================================================
 *
 * @description This function handles all social login logic after the social user
 * has been authenticated and userpayload is present. The payload MUST contain the
 * specified fields because this funciton will create a new user if the authenticated
 * user does not exist.
 *
 * @param {HandleSocialDbFunctionParams} params - function parameters inside an object
 *
 * @returns {Promise<HandleSocialDbFunctionReturn>} - Response object
 */
export type HandleSocialDbFunction = (
    params: HandleSocialDbFunctionParams
) => Promise<APILoginFunctionReturn>;

export type ApiReauthUserReturn = {
    success: boolean;
    payload?: { [key: string]: any } | null;
    msg?: string;
    userId?: string | number;
};

export type GoogleAccessTokenObject = {
    access_token: string;
    token_type: "Bearer";
    expires_in: number;
    scope: string;
    authuser: string;
    prompt: string;
};

export type GoogleOauth2User = {
    sub: string;
    name: string;
    given_name: string;
    family_name: string;
    picture: string;
    email: string;
    email_verified: boolean;
};

export interface AceEditorOptions {
    animatedScroll?: boolean;
    autoScrollEditorIntoView?: boolean;
    behavioursEnabled?: boolean;
    copyWithEmptySelection?: boolean;
    cursorStyle?: "ace" | "slim" | "smooth" | "wide";
    customScrollbar?: boolean;
    displayIndentGuides?: boolean;
    dragDelay?: number;
    dragEnabled?: boolean;
    enableAutoIndent?: boolean;
    enableBasicAutocompletion?: boolean | any[];
    enableKeyboardAccessibility?: boolean;
    enableLiveAutocompletion?: boolean | any[];
    enableMobileMenu?: boolean;
    enableMultiselect?: boolean;
    enableSnippets?: boolean;
    fadeFoldWidgets?: boolean;
    firstLineNumber?: number;
    fixedWidthGutter?: boolean;
    focusTimeout?: number;
    foldStyle?: "markbegin" | "markbeginend" | "manual";
    fontFamily?: string;
    fontSize?: number;
    hScrollBarAlwaysVisible?: boolean;
    hasCssTransforms?: boolean;
    highlightActiveLine?: boolean;
    highlightGutterLine?: boolean;
    highlightIndentGuides?: boolean;
    highlightSelectedWord?: boolean;
    indentedSoftWrap?: boolean;
    keyboardHandler?: string;
    liveAutocompletionDelay?: number;
    liveAutocompletionThreshold?: number;
    maxLines?: number;
    maxPixelHeight?: number;
    mergeUndoDeltas?: boolean | "always";
    minLines?: number;
    mode?: string;
    navigateWithinSoftTabs?: boolean;
    newLineMode?: AceAjax.NewLineMode;
    overwrite?: boolean;
    placeholder?: string;
    printMargin?: number | boolean;
    printMarginColumn?: number;
    readOnly?: boolean;
    relativeLineNumbers?: boolean;
    scrollPastEnd?: number;
    scrollSpeed?: number;
    selectionStyle?: string;
    session?: any;
    showFoldWidgets?: boolean;
    showFoldedAnnotations?: boolean;
    showGutter?: boolean;
    showInvisibles?: boolean;
    showLineNumbers?: boolean;
    showPrintMargin?: boolean;
    tabSize?: number;
    textInputAriaLabel?: string;
    theme?: string;
    tooltipFollowsMouse?: boolean;
    useSoftTabs?: boolean;
    useSvgGutterIcons?: boolean;
    useWorker?: boolean;
    vScrollBarAlwaysVisible?: boolean;
    value?: string;
    wrap?: number | boolean | "off" | "free" | "printmargin";
    wrapBehavioursEnabled?: boolean;
    wrapMethod?: "code" | "text" | "auto";
}

export type SendOneTimeCodeEmailResponse = {
    success: boolean;
    code?: string;
    createdAt?: number;
    email?: string;
    msg?: string;
};

export type CookieObject = {
    name: string;
    value: string;
    domain?: string;
    path?: string;
    expires?: Date;
    maxAge?: number;
    secure?: boolean;
    httpOnly?: boolean;
    sameSite?: "Strict" | "Lax" | "None";
    priority?: "Low" | "Medium" | "High";
};

export type HttpRequestParams<
    ReqObj extends { [k: string]: any } = { [k: string]: any }
> = RequestOptions & {
    scheme?: "http" | "https";
    body?: ReqObj;
    query?: ReqObj;
    urlEncodedFormBody?: boolean;
};

export type HttpRequestFunction<
    ReqObj extends { [k: string]: any } = { [k: string]: any },
    ResObj extends { [k: string]: any } = { [k: string]: any }
> = (param: HttpRequestParams<ReqObj>) => Promise<HttpFunctionResponse<ResObj>>;

export type HttpFunctionResponse<
    ResObj extends { [k: string]: any } = { [k: string]: any }
> = {
    status: number;
    data?: ResObj;
    error?: string;
    str?: string;
    requestedPath?: string;
};

export type ApiGetQueryObject<
    T extends { [k: string]: any } = { [k: string]: any }
> = {
    query: ServerQueryParam<T>;
    table: string;
    dbFullName?: string;
};

export const DataCrudRequestMethods = ["GET", "POST", "PUT", "DELETE"] as const;

export type DsqlMethodCrudParam<
    T extends { [key: string]: any } = { [key: string]: any }
> = {
    method: (typeof DataCrudRequestMethods)[number];
    body?: T;
    query?: DsqlCrudQueryObject<T>;
    tableName: string;
    addUser?: {
        field: keyof T;
    };
    user?: DATASQUIREL_LoggedInUser;
    extraData?: T;
    transformData?: DsqlCrudTransformDataFunction<T>;
    transformQuery?: DsqlCrudTransformQueryFunction<T>;
    existingData?: T;
    targetId?: string | number;
    sanitize?: (data?: T) => T;
    debug?: boolean;
};

export type DsqlCrudTransformDataFunction<
    T extends { [key: string]: any } = { [key: string]: any }
> = (params: {
    data: T;
    user?: DATASQUIREL_LoggedInUser;
    existingData?: T;
    reqMethod: (typeof DataCrudRequestMethods)[number];
}) => Promise<T>;

export type DsqlCrudTransformQueryFunction<
    T extends { [key: string]: any } = { [key: string]: any }
> = (params: {
    query: DsqlCrudQueryObject<T>;
    user?: DATASQUIREL_LoggedInUser;
    reqMethod: (typeof DataCrudRequestMethods)[number];
}) => Promise<DsqlCrudQueryObject<T>>;

export const DsqlCrudActions = ["insert", "update", "delete", "get"] as const;

export type DsqlCrudQueryObject<
    T extends { [key: string]: any } = { [key: string]: any }
> = ServerQueryParam<T> & {
    query?: ServerQueryQueryObject<T>;
};

export type DsqlCrudParam<
    T extends { [key: string]: any } = { [key: string]: any }
> = {
    action: (typeof DsqlCrudActions)[number];
    table: string;
    data?: T;
    targetId?: string | number;
    query?: DsqlCrudQueryObject<T>;
    sanitize?: (data?: T) => T;
    debug?: boolean;
};
