import type z from 'zod';

import type {
    CONNECTOR_VISIBILITY_MODE,
    CSVDelimiter,
    CSVEncoding,
    ConnectorType,
} from '../../../constants';
import type {
    ConnectionData,
    ConnectionTypedQueryApiRequest,
    ConnectionTypedQueryApiResponse,
    DATASET_FIELD_TYPES,
    TransferNotification,
    ValueOf,
    WorkbookId,
} from '../../../types';
import type {deleteConnectionResultSchema} from '../schemas/connections';

import type {WorkbookIdArg} from './common';

type BICounter = {
    id: string;
    name: string;
};

type BaseArgs = {
    connectionId: string;
};

type BaseConnectorItem = {
    conn_type: ConnectorType;
    backend_driven_form: boolean;
    hidden: boolean;
    history: boolean;
    title: string;
    /**
     * Controls the behavior of connector's list item in the list.
     *
     * 1. `free` - connector **is** shown in the list and **is** available for creation
     * 2. `hidden` - connector **is not** shown in the list and **is** available for creation
     * 3. `uncreatable` - connector **is not** shown in the list and **is not** available for creation
     * 4. `business` - connector **is** shown in the list and **is not** available for creation
     */
    visibility_mode: ValueOf<typeof CONNECTOR_VISIBILITY_MODE>;
    alias?: string;
};

export type ConnectorItem = BaseConnectorItem & {
    includes?: BaseConnectorItem[];
};

export type ConnectorItemSection = {
    title: string;
    connectors: ConnectorItem[];
};

export type EnsureUploadRobotResponse = {
    svc_acct_id: string;
    svc_acct_key_id: string;
    svc_acct_private_key: string;
};

export type EnsureUploadRobotArgs = BaseArgs;

export type GetAvailableCountersResponse = {
    counters: BICounter[];
};

export type GetAvailableCountersArgs = BaseArgs;

export type DeleteConnectionResponse = z.infer<typeof deleteConnectionResultSchema>;

export type GetConnectorsResponse = {
    /** @deprecated use `sections` & `uncategorized` fields instead */
    result: ConnectorItem[];
    /** Represent groups of connectors */
    sections?: ConnectorItemSection[];
    /** Represent connectors out of groups. These one should be rendered before grouped connectors */
    uncategorized?: ConnectorItem[];
};

export type GetConnectionResponse = ConnectionData;

export type GetConnectionArgs = BaseArgs & {
    workbookId?: WorkbookId;
    bindedDatasetId?: string | null;
    rev_id?: string;
};

export type CreateConnectionResponse = {
    id: string;
};

export type ConnectionErrorResponse = {
    code: string;
    message: string;
    details: {data: unknown};
};

export type CreateConnectionArgs = ConnectionData;

export type UpdateConnectionResponse = {};

export type UpdateConnectionArgs = {
    connectionId: string;
    data: ConnectionData;
};

export type VerifyConnectionResponse = {};

export type VerifyConnectionArgs = BaseArgs & ConnectionData & WorkbookIdArg;

export type VerifyConnectionParamsResponse = {};

export type VerifyConnectionParamsArgs = ConnectionData;

export type GetConnectionSourcesResponse = {
    sources: Record<string, string>[];
    freeform_sources: Record<string, string>[];
};

export type GetConnectionSourcesArgs = BaseArgs & WorkbookIdArg;

export type GetConnectionSourceSchemaResponse = {
    raw_schema: Record<string, string>[];
};

export type GetConnectionSourceSchemaArgs = BaseArgs &
    WorkbookIdArg & {
        source: {
            title: string;
            group: string[];
            id: string;
        };
    };

export type GetConnectionTypedQueryDataArgs = BaseArgs &
    WorkbookIdArg & {body: ConnectionTypedQueryApiRequest};

export type GetConnectionTypedQueryDataResponse = ConnectionTypedQueryApiResponse;

export type GetConnectionTypedQueryErrorResponse = {
    status: number;
    message: string;
    code: string;
    details?: {
        title?: string;
        description?: string;
        db_message?: string;
    };
    requestId: string;
};

export type ConnectorIconView = 'standard' | 'nav';

type ConnectorIconDataMap = Record<ConnectorIconView, string>;

export type ConnectorIconData = {conn_type: string} & (
    | {
          /** Indicates that icons data store in base64 format. */
          type: 'data';
          /** Map of links to sources on s3 or icons in base64 format. */
          data: ConnectorIconDataMap;
      }
    | {
          /** Indicates that icons data store as links on cdn. */
          type: 'url';
          /** Map of links to sources on s3 or icons in base64 format. */
          url: ConnectorIconDataMap;
      }
);

export type ListConnectorIconsResponse = {
    icons: ConnectorIconData[];
};

export type ExportConnectionArgs = {
    connectionId: string;
    workbookId?: string | null;
};

export type ExportConnectionResponse = {
    connection: ConnectionData;
    notifications: TransferNotification[];
};

export type ImportConnectionResponse = {
    id: string;
    notifications: TransferNotification[];
};

export type ImportConnectionArgs = {
    workbookId: string;
    connection: ConnectionData;
};

export type StateStatus = 'ready' | 'in_progress' | 'failed';
export type RefreshToken = string | null | undefined;

export type GetFileStatusResponse = {
    file_id: string;
    status: StateStatus;
    errors: {
        code: string;
        details: {
            token: string | null;
            row: number;
            column: number;
        };
        level: string;
        message: string;
    }[];
    error?: {
        code: string;
    };
};

export type GetFileStatusArgs = {
    fileId: string;
};

export type FileSourceInfo = {
    is_applicable: boolean;
    source_id: string;
    title: string;
    error?: {code: string} | null;
};

export type GetFileSourcesResponse = {
    file_id: string;
    sources: FileSourceInfo[];
};

export type GetFileSourcesArgs = {
    fileId: string;
};

export type GetFileSourceStatusResponse = {
    file_id: string;
    source_id: string;
    status: StateStatus;
};

export type GetFileSourceStatusArgs = {
    fileId: string;
    sourceId: string;
};

export type FileSourceDataSettings = {
    delimiter: CSVDelimiter;
    encoding: CSVEncoding;
    first_line_is_header: boolean;
};

export type FileSourceSchema =
    | {
          user_type: DATASET_FIELD_TYPES;
          title: string;
          name: string;
      }[]
    | null;

export type FileSourcePreview = (string | number)[][];

export type UpdateFileSourceResponse = {
    data_settings: FileSourceDataSettings;
    file_id: string;
    options: {
        columns: {
            name: string;
            user_type: DATASET_FIELD_TYPES[];
        }[];
        data_settings: {
            delimiter: CSVDelimiter[];
            encoding: CSVEncoding[];
        };
    } | null;
    source: {
        is_valid: boolean;
        preview: FileSourcePreview;
        raw_schema: FileSourceSchema;
        sheet_id: S3BasedConnectionSheetId;
        source_id: string;
        title: string;
        error?: {
            code: string;
            details: {'request-id': string};
            level: string;
            message: string;
        };
        private_path?: string;
        public_link?: string;
        spreadsheet_id?: string;
    };
};

export type FileSourceColumnType = {
    name: string;
    user_type: DATASET_FIELD_TYPES;
};

export type UpdateFileSourceArgs = {
    fileId: string;
    sourceId: string;
    // The field is in the snake case, because it is passed directly to backend request
    column_types?: FileSourceColumnType[];
};

export type ApplySourceSettingsResponse = {};

export type ApplySourceSettingsArgs = {
    fileId: string;
    sourceId: string;
    // The field is in the snake case, because it is passed directly to backend request
    data_settings: FileSourceDataSettings;
    title?: string;
};

export type AddGoogleSheetResponse = {
    file_id: string;
    title: string;
};

export type AddGoogleSheetArgs = {
    type: 'gsheets';
    url: string;
    authorized: boolean;
    refresh_token?: RefreshToken;
    connection_id?: string;
};

export type UpdateS3BasedConnectionDataResponse = {
    files: {
        file_id: string;
        sources: {
            source_id: string;
        }[];
    }[];
};

type BaseUpdatedSource = {
    id: string;
    title: string;
    first_line_is_header: boolean;
};

type S3BasedConnectionSheetId = string | number;

export type GoogleSheetUpdatedSource = BaseUpdatedSource & {
    sheet_id: S3BasedConnectionSheetId;
    spreadsheet_id?: string;
};

export type YandexDocumentUpdatedSource = BaseUpdatedSource & {
    public_link?: string;
    private_path?: string;
    sheet_id?: S3BasedConnectionSheetId;
};

type UpdateGoogleSheetDataArgs = {
    type: 'gsheets';
    sources: GoogleSheetUpdatedSource[];
    refresh_token?: RefreshToken;
};

type UpdateYandexDocumentDataArgs = {
    type: 'yadocs';
    sources: YandexDocumentUpdatedSource[];
    oauth_token?: string;
};

export type UpdateS3BasedConnectionDataArgs = (
    | UpdateGoogleSheetDataArgs
    | UpdateYandexDocumentDataArgs
) & {
    authorized: boolean;
    connection_id?: string;
};

export type AddYandexDocumentResponse = {
    file_id: string;
    title: string;
};

export type AddYandexDocumentArgs = {
    authorized: boolean;
    type: 'yadocs';
    connection_id?: string;
    private_path?: string;
    public_link?: string;
    oauth_token?: RefreshToken;
};

export type GetPresignedUrlResponse = {
    url: string;
    fields: Record<string, string>;
};

export type DownloadPresignedUrlArgs = {
    filename: string;
    key: string;
};

export type DownloadPresignedUrlResponse = {
    file_id: string;
    filename: string;
};
