import type {
	ICredentialsBase,
	IExecutionBase,
	IExecutionDb,
	ITagBase,
	IWorkflowDb,
} from '@n8n/db';
import type { AssignableGlobalRole } from '@n8n/permissions';
import type { IDeferredPromise } from '@n8n/utils/promise/deferred-promise';
import type { Application, Response } from 'express';
import type {
	ExecutionError,
	ICredentialDataDecryptedObject,
	ICredentialsDecrypted,
	IExecuteResponsePromiseData,
	IRun,
	ITelemetryTrackProperties,
	IWorkflowBase,
	CredentialLoadingDetails,
	WorkflowExecuteMode,
	ExecutionStatus,
	ExecutionSummary,
	IWorkflowExecutionDataProcess,
	IExecutionContext,
	WorkflowExecutionSource,
} from 'n8n-workflow';
import type PCancelable from 'p-cancelable';

import type { ActiveWorkflowManager } from '@/active-workflow-manager';
import type { ExternalHooks } from '@/external-hooks';

export interface ICredentialsTypeData {
	[key: string]: CredentialLoadingDetails;
}

export interface ICredentialsOverwrite {
	[key: string]: ICredentialDataDecryptedObject;
}

// ----------------------------------
//               tags
// ----------------------------------

export interface ITagToImport extends ITagBase {
	createdAt?: string;
	updatedAt?: string;
}

// ----------------------------------
//            workflows
// ----------------------------------

export interface IWorkflowResponse extends IWorkflowBase {
	id: string;
}

export interface IWorkflowVersionMetadata {
	versionMetadata?: {
		name: string | null;
		description: string | null;
	} | null;
}

export interface IWorkflowToImport
	extends Omit<
			IWorkflowBase,
			'staticData' | 'pinData' | 'createdAt' | 'updatedAt' | 'activeVersion'
		>,
		IWorkflowVersionMetadata {
	owner?:
		| {
				type: 'personal';
				personalEmail: string;
		  }
		| {
				type: 'team';
				teamId: string;
				teamName: string;
		  };
	parentFolderId: string | null;
}

export type IWorkflowWithVersionMetadata = IWorkflowDb & IWorkflowVersionMetadata;

// ----------------------------------
//            credentials
// ----------------------------------

export type ICredentialsDecryptedDb = ICredentialsBase & ICredentialsDecrypted;

export type ICredentialsDecryptedResponse = ICredentialsDecryptedDb;

export type SaveExecutionDataType = 'all' | 'none';

/** Payload for updating an execution. */
export type UpdateExecutionPayload = Omit<IExecutionDb, 'id' | 'createdAt' | 'storedAt'>;

// Flatted data to save memory when saving in database or transferring
// via REST API
export interface IExecutionFlatted extends IExecutionBase {
	data: string;
	workflowData: IWorkflowBase;
}

export interface IExecutionFlattedResponse extends IExecutionFlatted {
	id: string;
	retryOf?: string;
	/** See {@link IExecutionResponse.dataTooLargeToDisplay}. When true, `data` is empty. */
	dataTooLargeToDisplay?: boolean;
}

export interface IExecutionsListResponse {
	count: number;
	results: ExecutionSummary[];
	estimated: boolean;
}

export interface ExecutionStopResult {
	finished?: boolean;
	mode: WorkflowExecuteMode;
	startedAt: Date;
	stoppedAt?: Date;
	status: ExecutionStatus;
}

export interface IExecutionsCurrentSummary {
	id: string;
	retryOf?: string;
	startedAt: Date;
	mode: WorkflowExecuteMode;
	workflowId: string;
	status: ExecutionStatus;
}

/**
 * An already-persisted execution a process wants to take over, plus the status it must
 * still be in for the claim to succeed. The status travels with the id so the takeover
 * is a compare-and-swap: if the row moved on, another process already claimed it.
 */
export interface ResumableExecution {
	executionId: string;
	/** `waiting` for a row being resumed, `new` for one enqueued before a restart. */
	expectedStatus: Extract<ExecutionStatus, 'new' | 'waiting'>;
}

export interface IExecutingWorkflowData {
	executionData: IWorkflowExecutionDataProcess;
	startedAt: Date;
	/** This promise rejects when the execution is stopped. When the execution finishes (successfully or not), the promise resolves. */
	postExecutePromise: IDeferredPromise<IRun | undefined>;
	/** HTTPResponse needed for streaming responses */
	httpResponse?: Response;
	responsePromise?: IDeferredPromise<IExecuteResponsePromiseData>;
	workflowExecution?: PCancelable<IRun>;
	status: ExecutionStatus;
}

export interface IActiveDirectorySettings {
	enabled: boolean;
}

export interface IPackageVersions {
	cli: string;
}

export interface IWorkflowErrorData {
	[key: string]: any;
	execution?: {
		id?: string;
		url?: string;
		retryOf?: string;
		error: ExecutionError;
		lastNodeExecuted: string;
		mode: WorkflowExecuteMode;
		executionContext?: IExecutionContext;
	};
	trigger?: {
		error: ExecutionError;
		mode: WorkflowExecuteMode;
	};
	workflow: {
		id?: string;
		name: string;
	};
}

export interface IWorkflowStatisticsDataLoaded {
	dataLoaded: boolean;
}

// ----------------------------------
//               telemetry
// ----------------------------------

export interface IExecutionTrackProperties extends ITelemetryTrackProperties {
	workflow_id: string;
	success: boolean;
	error_node_type?: string;
	is_manual: boolean;
	crashed?: boolean;
	used_end_user_credentials?: boolean;
	/** Number of nodes that attempted to resolve an end-user credential (regardless of success). */
	end_user_credentials_attempted_count?: number;
	/** Number of nodes that successfully resolved an end-user credential. */
	end_user_credentials_resolved_count?: number;
	/** Effective resolver id the execution ran with (workflow override or seeded system resolver). */
	credential_resolver_id?: string;
	execution_source?: WorkflowExecutionSource;
	mock_data_sources?: string;
}

export interface IAgentExecutionTrackProperties extends ITelemetryTrackProperties {
	agent_id: string;
	/**
	 * n8n user ID, present only when the agent run has direct n8n user context —
	 * so in-app chat and manual task runs, but never chat integrations or cron.
	 */
	user_id?: string;
	run_type: AgentRunTelemetryType;
	/**
	 * Fresh user turns only. Resume continuations and delegated child runs do not
	 * increment this count.
	 */
	message_count?: number;
	/** AI SDK usage from agent, title, memory generation, and embedding calls. */
	token_count?: number;
	/** Tool invocations only. Resuming a suspended tool does not double-count it. */
	tool_call_count?: number;
}

export type AgentRunTelemetryType = 'test' | 'production';

export type AgentTurnTelemetryStatus = 'succeeded' | 'failed';

export type AgentTelemetryMemoryType =
	| 'none'
	| 'n8n'
	| 'n8n_observational'
	| 'n8n_episodic'
	| 'n8n_observational_episodic';

export interface IAgentConfigurationTelemetryProperties {
	model: string | null;
	channels: string[];
	tool_types: string[];
	tool_count: number;
	num_skills: number;
	memory_type: AgentTelemetryMemoryType;
}

export interface IAgentTurnFinishedTrackProperties extends ITelemetryTrackProperties {
	agent_id: string;
	/** Internal aggregation key only. This must never be emitted to telemetry. */
	thread_id: string;
	run_type: AgentRunTelemetryType;
	/** Absent for saved agents; 'inline' for node-embedded agent definitions. */
	agent_type?: 'inline';
	turn_status: AgentTurnTelemetryStatus;
	configuration: IAgentConfigurationTelemetryProperties;
	latency_ms: number;
	cost: number;
	/**
	 * Tokens for this turn only, from the same recorded usage as `cost` — so the
	 * two reconcile. Narrower than the token count on `Agent execution count`,
	 * which also covers LLM calls belonging to no turn.
	 */
	token_count: number;
	tool_call_count: number;
}

// ----------------------------------
//               license
// ----------------------------------

export interface ILicenseReadResponse {
	usage: {
		activeWorkflowTriggers: {
			limit: number;
			value: number;
			warningThreshold: number;
		};
		workflowsHavingEvaluations: {
			limit: number;
			value: number;
		};
	};
	license: {
		planId: string;
		planName: string;
	};
}

export interface ILicensePostResponse extends ILicenseReadResponse {
	managementToken: string;
}

export interface Invitation {
	email: string;
	role: AssignableGlobalRole;
}

export interface N8nApp {
	app: Application;
	restEndpoint: string;
	externalHooks: ExternalHooks;
	activeWorkflowManager: ActiveWorkflowManager;
}
