import { Api as ApiPb, Trigger_Job, Trigger_Workflow } from '@superblocksteam/types';
import { Metadata, UserType as ProtoUserType } from '@superblocksteam/types';

import { Param } from '../common/param.js';
import { DatasourceEnvironments } from '../datasource/index.js';
import { IntegrationDto } from '../integration/index.js';
import { EntityProfileSettings } from '../profile/index.js';
import { IResourceMetadata } from '../resource/index.js';
import { Action, ActionId } from './action.js';
import { ExecutionParam } from './execution.js';
import { Global } from './global.js';
import { ScheduleState } from './schedule.js';

// ApiNotificationConfiguration configures how the UI should be informed after
// an API runs.
export type ApiNotificationConfiguration = {
  onSuccess?: {
    enabled?: boolean;
    customText?: string;
  };
  onError?: {
    enabled?: boolean;
    includeError?: boolean;
    customText?: string;
    customDescription?: string;
  };
};

export interface Api {
  id: string;
  environment: DatasourceEnvironments;
  profile: string;
  applicationId?: string | null;
  apiPb?: ApiPb;
  triggerType: ApiTriggerType;
}

export type ApiDetails = {
  name: string;
  triggerActionId: ActionId;
  actions: {
    [key: string]: Action;
  };
  executeOnPageLoad?: boolean;
  notificationConfig?: ApiNotificationConfiguration;
  bindings?: string[];
  dynamicBindingPathList?: Param[];
  version?: string;
  deactivated?: Date;
  created?: Date;
  updated?: Date;
  supportedMethod?: 'GET' | 'POST';
  workflowParams?: ExecutionParam[];
};

// Full API definition including datasource and plugin
export type ApiDefinition = {
  api: Api;
  orgApiKey: string; // to authenticate dependent workflows
  organizationId: string; // for traces
  global: Global;
  locationContext?: ApiLocationContext;
  metadata?: ApiDefinitionMetadata;
};

// ApiLocationContext locates an API
export type ApiLocationContext = {
  applicationId: string;
  pageId?: string; // @deprecated orchestrator no longer uses this field
};

type ApiDefinitionMetadata = {
  requester: string;
  requesterType?: ProtoUserType;
  organizationName?: string;
};

export enum ApiTriggerType {
  UI,
  WORKFLOW,
  SCHEDULE
}

export enum ApiTriggerTypeQuery {
  UI = 'ui',
  WORKFLOW = 'workflow',
  SCHEDULE = 'schedule'
}

export function apiTriggerTypeQueryToType(trigger: ApiTriggerTypeQuery): ApiTriggerType {
  switch (trigger) {
    case ApiTriggerTypeQuery.UI:
      return ApiTriggerType.UI;
    case ApiTriggerTypeQuery.WORKFLOW:
      return ApiTriggerType.WORKFLOW;
    case ApiTriggerTypeQuery.SCHEDULE:
      return ApiTriggerType.SCHEDULE;
  }
}

export interface IApiV3Dto {
  id: string;
  name: string;
  applicationId?: string | null;
  pageId?: string | null;
  organizationId: string;
  apiPb?: ApiPb;
  triggerType: ApiTriggerType;
  updated: number | Date;
  canDelete?: boolean;
  scheduleState?: ScheduleState;
  folderId?: string | null;
  isDeployed?: boolean;
  deployedCommitId?: string;
  sendEmailOnFailure?: boolean;
  integrations?: Record<string, IntegrationDto>;
  creator?: {
    id: string;
    name: string;
  };
  settings?: ApiSettings;
  repoConnection?: { created: Date } | null;
  restricted?: boolean;
}

// This represents the data needed to populate the homepage cards for
// workflows and scheduled jobs
export interface IHomepageApiV3Dto extends IResourceMetadata {
  triggerType?: ApiTriggerType;
  scheduleState?: ScheduleState;
  creator?: {
    id: string;
    name: string;
    email: string;
  };
}

//TODO(alex): look into defining exported types in protobuf instead of deriving them here
type protoMethods = 'equals' | 'clone' | 'fromBinary' | 'fromJson' | 'fromJsonString' | 'toBinary' | 'toJson' | 'toJsonString' | 'getType';

export const EXPORTED_METADATA_EXCLUDED_FIELDS = ['description', 'folder', 'tags', 'timestamps', 'version'] as const;

type ExcludedFields = (typeof EXPORTED_METADATA_EXCLUDED_FIELDS)[number];

type ExportedApiPbMetadata = Omit<Metadata, ExcludedFields | protoMethods>;

export type ApiPbTrigger = {
  workflow?: Trigger_Workflow;
  job?: Trigger_Job;
};

export type ExportedApiPbTrigger = {
  workflow?: Omit<Trigger_Workflow, 'options' | protoMethods>;
  job?: Omit<Trigger_Job, 'options' | protoMethods>;
};

export type ExportedApiPb = Omit<ApiPb, 'metadata' | 'trigger' | protoMethods> & {
  metadata: ExportedApiPbMetadata;
  trigger: ExportedApiPbTrigger | undefined;
};

export type ExportedApiV3Dto = Omit<IApiV3Dto, 'updated' | 'triggerType' | 'apiPb' | 'organizationId'> & {
  apiPb?: ExportedApiPb;
};

export type ApiSettings = EntityProfileSettings;

export { ViewMode as OrchestratorViewMode } from '@superblocksteam/types';
export * from './action.js';
export * from './resolvedActionProp.js';
export * from './schedule.js';
export * from './execution.js';
export * from './global.js';
export * from './control-flow.js';
