/**
 * Pipeline Engine Types
 */

export type TriggerSource = 'datto_rmm' | 'autotask' | 'veeam' | 'manual';

export type StepType =
  | 'filter'
  | 'transform'
  | 'set_variable'
  | 'delay'
  | 'enrich_device'
  | 'enrich_company'
  | 'enrich_ticket'
  | 'create_ticket'
  | 'update_ticket'
  | 'create_note'
  | 'ai_analyze'
  | 'notify'
  | 'approval'
  | 'rmm_quick_job'
  | 'rmm_get_job_results';

export type ChannelType = 'teams' | 'telegram' | 'ntfy' | 'webhook';

export type PipelineStatus = 'pending' | 'running' | 'waiting' | 'completed' | 'failed' | 'skipped';
export type StepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'waiting' | 'skipped';
export type ApprovalStatus = 'pending' | 'approved' | 'rejected' | 'timeout';
export type OnFailure = 'continue' | 'stop' | 'skip_to';

export interface TriggerCondition {
  field: string;
  operator: 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'in' | 'not_in' | 'regex' | 'exists' | 'not_exists';
  value: any;
}

// ============================================================================
// DB Row Types
// ============================================================================

export interface NotificationChannel {
  id: number;
  name: string;
  channel_type: ChannelType;
  config: Record<string, any>;
  is_active: boolean;
  owner_user_id: string | null;
  created_at: Date;
  updated_at: Date;
}

export interface WebhookPipeline {
  id: number;
  name: string;
  description: string | null;
  is_active: boolean;
  trigger_source: TriggerSource;
  trigger_conditions: TriggerCondition[];
  sort_order: number;
  created_at: Date;
  updated_at: Date;
}

export interface PipelineStep {
  id: number;
  pipeline_id: number;
  step_order: number;
  step_type: StepType;
  name: string;
  config: Record<string, any>;
  on_failure: OnFailure;
  skip_to_step: number | null;
  is_active: boolean;
  timeout_ms: number | null;
  created_at: Date;
  updated_at: Date;
}

export interface PipelineExecution {
  id: number;
  pipeline_id: number;
  trigger_source: string;
  trigger_payload: Record<string, any> | null;
  status: PipelineStatus;
  current_step: number | null;
  context: Record<string, any>;
  started_at: Date;
  completed_at: Date | null;
  duration_ms: number | null;
  error_message: string | null;
  created_at: Date;
}

export interface PipelineExecutionStep {
  id: number;
  execution_id: number;
  step_order: number;
  step_type: string;
  step_name: string | null;
  status: StepStatus;
  input_data: Record<string, any> | null;
  output_data: Record<string, any> | null;
  started_at: Date | null;
  completed_at: Date | null;
  duration_ms: number | null;
  error_message: string | null;
}

export interface ApprovalRequest {
  id: number;
  execution_id: number;
  step_order: number;
  channel_id: number | null;
  message: string;
  options: string[];
  status: ApprovalStatus;
  responded_by: string | null;
  responded_at: Date | null;
  response_data: Record<string, any> | null;
  expires_at: Date | null;
  created_at: Date;
}

// ============================================================================
// Runtime Types
// ============================================================================

export interface PipelineContext {
  [key: string]: any;
}

export interface StepExecutorResult {
  success: boolean;
  output?: Record<string, any>;
  error?: string;
  waiting?: boolean; // true if step is paused (e.g., approval)
}

export interface PipelineWithSteps extends WebhookPipeline {
  steps: PipelineStep[];
}

// ============================================================================
// API Types
// ============================================================================

export interface PipelineInput {
  name: string;
  description?: string;
  is_active?: boolean;
  trigger_source: TriggerSource;
  trigger_conditions?: TriggerCondition[];
  sort_order?: number;
}

export interface PipelineStepInput {
  step_order: number;
  step_type: StepType;
  name: string;
  config?: Record<string, any>;
  on_failure?: OnFailure;
  skip_to_step?: number;
  is_active?: boolean;
  timeout_ms?: number;
}

export interface NotificationChannelInput {
  name: string;
  channel_type: ChannelType;
  config: Record<string, any>;
  is_active?: boolean;
}

// ============================================================================
// Phase 9 — Event taxonomy + user subscriptions
// ============================================================================

export interface NotifyEventKey {
  key: string;
  display_label: string;
  description: string | null;
  sort_order: number;
  is_active: boolean;
  created_at: Date;
  updated_at: Date;
}

export interface UserEventSubscription {
  user_id: string;
  event_key: string;
  channel_type: ChannelType;
  enabled: boolean;
  updated_at: Date;
}

// ============================================================================
// Phase 9 — notify step per-user routing (ROUTE-01..06)
// ============================================================================

/** Resolver name; resolvers live in lib/services/pipeline-steps/notify-resolvers.ts. */
export type ResolverName = 'autotask_resource_email' | 'direct_email' | 'pulse_user_id' | string;

/** Optional block on a `notify` step's config. When present, the step attempts
 *  delivery via the resolved Pulse user's personal channel before falling back
 *  to the step's `channel_id`.
 *
 *  v1 limitation: `field` is a single-level key; dotted paths like 'company.id'
 *  are NOT walked. Admins must surface needed values at top level of the source
 *  object (e.g., via an upstream transform step). */
export interface RouteToUser {
  /** PipelineContext key whose value holds the entity (e.g. 'ticket'). */
  source: string;
  /** Single-level field name within context[source] (e.g. 'assignedResourceID').
   *  v1 only: single-level lookup — dotted paths like 'company.id' are NOT walked. */
  field: string;
  /** Resolver name. Looks up the user from the field value. */
  resolve: ResolverName;
  /** Event key checked against user_event_subscriptions for muting (D-12). */
  event_key: string;
  /** Optional preferred channel type (D-10). When omitted: ntfy then teams then fallback. */
  channel_type?: 'teams' | 'ntfy';
}

/** Output of a resolver. null = no recipient (notify.ts falls through to global). */
export type ResolvedRecipient =
  | { user_id: string }
  | { email: string }
  | null;

/** A resolver fn. Pure async; reads from postgres if it needs to. */
export type NotifyResolver = (fieldValue: unknown) => Promise<ResolvedRecipient>;

/** Reasons recorded in execution_step.output_data when fallback occurs (D-11). */
export type UserRouteFallbackReason =
  | 'no_channel'
  | 'send_failed'
  | 'user_not_found'
  | 'no_field_value'
  | 'resolver_unknown';

export interface UserRouteFallback {
  reason: UserRouteFallbackReason;
  user_id?: string;
  channel_type: string;
  error?: string;
}
