/**
 * Automation Workflow Models
 *
 * Models for the automation workflow builder:
 * - AutomationWorkflow: Workflow definitions with nodes and edges
 * - AutomationInstance: Workflow execution instances per contact
 * - AutomationLog: Execution logs for analytics
 *
 * Inspired by Brevo, Mailchimp, and Zoho automation platforms.
 * Provider-independent architecture for future integrations.
 */

import mongoose, { Schema, Document, Types } from 'mongoose';

// ============================================
// TYPE DEFINITIONS
// ============================================

// Trigger Types
export type TriggerType =
  // Contact Triggers
  | 'trigger_subscribed'
  | 'trigger_form_submitted'
  | 'trigger_tag_added'
  | 'trigger_tag_removed'
  | 'trigger_purchase_made'
  | 'trigger_abandoned_cart'
  | 'trigger_link_clicked'
  | 'trigger_email_opened'
  | 'trigger_workflow_entered'
  | 'trigger_date_based'
  | 'trigger_api_call'
  | 'trigger_anniversary'
  | 'trigger_birthday';

// Node Types
export type NodeType =
  // Actions
  | 'action_send_email'
  | 'action_send_sms'
  | 'action_send_whatsapp'
  | 'action_add_tag'
  | 'action_remove_tag'
  | 'action_update_contact'
  | 'action_update_crm_field'
  | 'action_create_crm_task'
  | 'action_call_webhook'
  | 'action_send_notification'
  | 'action_ai_generate'
  // Flow Control
  | 'flow_delay'
  | 'flow_wait_until_date'
  | 'flow_wait_until_time'
  | 'flow_wait_until_event'
  | 'flow_condition'
  | 'flow_split'
  | 'flow_goal'
  | 'flow_exit'
  | 'flow_end';

// Workflow Status
export type WorkflowStatus = 'draft' | 'active' | 'paused' | 'archived';

// Instance Status
export type InstanceStatus = 'pending' | 'running' | 'paused' | 'completed' | 'exited' | 'error';

// Condition Operator
export type ConditionOperator =
  | 'equals'
  | 'not_equals'
  | 'contains'
  | 'not_contains'
  | 'starts_with'
  | 'ends_with'
  | 'greater_than'
  | 'less_than'
  | 'greater_or_equal'
  | 'less_or_equal'
  | 'is_empty'
  | 'is_not_empty'
  | 'is_true'
  | 'is_false'
  | 'before'
  | 'after'
  | 'between';

// ============================================
// INTERFACES
// ============================================

export interface ITriggerFilter {
  field: string;
  operator: ConditionOperator;
  value: any;
}

export interface IWorkflowTrigger {
  type: TriggerType;
  id: string;
  config: Record<string, any>;
  filters?: ITriggerFilter[];
}

export interface ICondition {
  field: string;
  operator: ConditionOperator;
  value: any;
}

export interface IConditionGroup {
  logic: 'all' | 'any';
  conditions: ICondition[];
}

export interface INodeConfig {
  // General configs
  label?: string;
  description?: string;

  // Provider-aware email configs (which email platform to use)
  emailProvider?: 'brevo' | 'mailchimp' | 'zoho';
  senderId?: number;
  senderEmail?: string;
  senderName?: string;
  emailHtmlContent?: string;
  emailHtmlUrl?: string;

  // Action configs
  emailTemplateId?: string;
  internalTemplateId?: string;  // Internal EmailDesignerTemplate ObjectId for template resolution
  contactListIds?: string[];     // Contact list IDs for recipient targeting
  emailSubject?: string;
  emailPreviewText?: string;
  emailFromName?: string;
  emailReplyTo?: string;
  smsTemplate?: string;
  smsSenderId?: string;
  whatsappTemplate?: string;
  whatsappTemplateParams?: Record<string, string>;
  tagName?: string;
  contactFields?: Record<string, any>;
  crmTaskType?: string;
  crmTaskTitle?: string;
  crmTaskDueDate?: string;
  crmTaskAssignTo?: string;
  webhookUrl?: string;
  webhookMethod?: 'GET' | 'POST' | 'PUT' | 'PATCH';
  webhookHeaders?: Record<string, string>;
  webhookBody?: Record<string, any>;
  notificationType?: 'info' | 'warning' | 'error';
  notificationMessage?: string;
  notificationRecipients?: string[];

  // Delay configs
  delayDuration?: number;
  delayUnit?: 'minutes' | 'hours' | 'days' | 'weeks';

  // Wait configs
  waitDateField?: string;
  waitTime?: string;
  waitEventTrigger?: string;
  waitTimeout?: number;

  // Condition configs
  conditions?: IConditionGroup[];
  conditionLogic?: 'all' | 'any';

  // Split configs
  splitPercentage?: number;

  // Goal configs
  goalType?: string;
  goalCriteria?: Record<string, any>;

  // Exit configs
  exitReason?: string;
}

export interface IWorkflowNode {
  id: string;
  type: NodeType;
  position: { x: number; y: number };
  data: Record<string, any>;
  config: INodeConfig;
}

export interface IWorkflowEdge {
  id: string;
  source: string;
  target: string;
  sourceHandle?: string;
  targetHandle?: string;
  label?: string;
  animated?: boolean;
}

export interface IWorkflowSettings {
  allowReentry: boolean;
  reentryCooldown?: number;
  timezone: string;
  notifyOnCompletion: boolean;
  notifyOnError: boolean;
  notificationEmails?: string[];
  testMode: boolean;
  testContactId?: string;
  // Email provider for this workflow
  platform?: 'brevo' | 'mailchimp' | 'zoho';
}

export interface IWorkflowStats {
  totalInstances: number;
  activeInstances: number;
  completedInstances: number;
  exitedInstances: number;
  errorInstances: number;
  lastTriggeredAt?: Date;
  averageCompletionTime?: number;
}

// Outcome of registering this workflow's trigger webhook on the email provider
// when it went active. Surfaces silent registration failures so an "active"
// workflow with a broken/absent webhook is visible instead of appearing healthy.
export type WebhookRegistrationStatus = 'not_required' | 'registered' | 'failed';

export interface IWebhookRegistration {
  status: WebhookRegistrationStatus;
  provider?: string;
  webhookId?: string;
  events?: string[];
  error?: string;
  updatedAt?: Date;
}

export interface IAutomationWorkflow extends Document {
  companyId: string;
  createdById: string;
  name: string;
  slug: string;
  description?: string;
  status: WorkflowStatus;
  trigger: IWorkflowTrigger;
  nodes: IWorkflowNode[];
  edges: IWorkflowEdge[];
  viewport: { x: number; y: number; zoom: number };
  version: number;
  publishedAt?: Date;
  publishedById?: string;
  settings: IWorkflowSettings;
  tags?: string[];
  category?: string;
  stats: IWorkflowStats;
  webhookRegistration?: IWebhookRegistration;
  createdAt: Date;
  updatedAt: Date;
  deletedAt?: Date;
}

export interface INodeExecutionState {
  nodeId: string;
  status: 'pending' | 'running' | 'completed' | 'skipped' | 'error';
  startedAt?: Date;
  completedAt?: Date;
  output?: Record<string, any>;
  error?: string;
}

export interface IInstanceError {
  nodeId: string;
  message: string;
  timestamp: Date;
  retryCount: number;
}

export interface IAutomationInstance extends Omit<Document, 'errors'> {
  companyId: string;
  workflowId: Types.ObjectId;
  workflowVersion: number;
  contactId: string;
  status: InstanceStatus;
  currentNodeId: string;
  executedNodes: string[];
  nodeStates: Map<string, INodeExecutionState>;
  enteredAt: Date;
  lastProcessedAt?: Date;
  completedAt?: Date;
  exitReason?: string;
  variables: Record<string, any>;
  executionErrors?: IInstanceError[];
  scheduledFor?: Date;
  waitingForEvent?: string;
  goalReached?: boolean;
  goalReachedAt?: Date;
  createdAt: Date;
  updatedAt: Date;
}

export interface IAutomationLog extends Document {
  companyId: string;
  instanceId: Types.ObjectId;
  workflowId: Types.ObjectId;
  nodeId: string;
  nodeType: string;
  action: string;
  status: 'started' | 'completed' | 'error' | 'skipped';
  input?: Record<string, any>;
  output?: Record<string, any>;
  error?: string;
  timestamp: Date;
  duration?: number;
}

// ============================================
// SCHEMAS
// ============================================

const TriggerFilterSchema = new Schema<ITriggerFilter>(
  {
    field: { type: String, required: true },
    operator: { type: String, enum: ['equals', 'not_equals', 'contains', 'not_contains', 'starts_with', 'ends_with', 'greater_than', 'less_than', 'greater_or_equal', 'less_or_equal', 'is_empty', 'is_not_empty', 'is_true', 'is_false', 'before', 'after', 'between'], required: true },
    value: { type: Schema.Types.Mixed, required: true },
  },
  { _id: false }
);

const WorkflowTriggerSchema = new Schema<IWorkflowTrigger>(
  {
    type: { type: String, required: true },
    id: { type: String, required: true },
    config: { type: Schema.Types.Mixed, default: {} },
    filters: [TriggerFilterSchema],
  },
  { _id: false }
);

const ConditionSchema = new Schema<ICondition>(
  {
    field: { type: String, required: true },
    operator: { type: String, required: true },
    value: { type: Schema.Types.Mixed, required: true },
  },
  { _id: false }
);

const ConditionGroupSchema = new Schema<IConditionGroup>(
  {
    logic: { type: String, enum: ['all', 'any'], default: 'all' },
    conditions: [ConditionSchema],
  },
  { _id: false }
);

const NodeConfigSchema = new Schema<INodeConfig>(
  {
    // General configs
    label: String,
    description: String,

    // Provider-aware email configs
    emailProvider: { type: String, enum: ['brevo', 'mailchimp', 'zoho'] },
    senderId: Number,
    senderEmail: String,
    senderName: String,
    emailHtmlContent: String,
    emailHtmlUrl: String,

    // Action configs
    emailTemplateId: String,
    internalTemplateId: String,  // Internal EmailDesignerTemplate ObjectId
    contactListIds: [String],     // Contact list IDs for recipient targeting
    emailSubject: String,
    emailPreviewText: String,
    emailFromName: String,
    emailReplyTo: String,
    smsTemplate: String,
    smsSenderId: String,
    whatsappTemplate: String,
    whatsappTemplateParams: Schema.Types.Mixed,
    tagName: String,
    contactFields: Schema.Types.Mixed,
    crmTaskType: String,
    crmTaskTitle: String,
    crmTaskDueDate: String,
    crmTaskAssignTo: String,
    webhookUrl: String,
    webhookMethod: { type: String, enum: ['GET', 'POST', 'PUT', 'PATCH'] },
    webhookHeaders: Schema.Types.Mixed,
    webhookBody: Schema.Types.Mixed,
    notificationType: { type: String, enum: ['info', 'warning', 'error'] },
    notificationMessage: String,
    notificationRecipients: [String],

    // Delay configs
    delayDuration: Number,
    delayUnit: { type: String, enum: ['minutes', 'hours', 'days', 'weeks'] },

    // Wait configs
    waitDateField: String,
    waitTime: String,
    waitEventTrigger: String,
    waitTimeout: Number,

    // Condition configs
    conditions: [ConditionGroupSchema],
    conditionLogic: { type: String, enum: ['all', 'any'] },

    // Split configs
    splitPercentage: Number,

    // Goal configs
    goalType: String,
    goalCriteria: Schema.Types.Mixed,

    // Exit configs
    exitReason: String,
  },
  { _id: false, strict: false }
);

const WorkflowNodeSchema = new Schema<IWorkflowNode>(
  {
    id: { type: String, required: true },
    type: { type: String, required: true },
    position: { x: Number, y: Number },
    data: Schema.Types.Mixed,
    config: NodeConfigSchema,
  },
  { _id: false, strict: false }
);

const WorkflowEdgeSchema = new Schema<IWorkflowEdge>(
  {
    id: { type: String, required: true },
    source: { type: String, required: true },
    target: { type: String, required: true },
    sourceHandle: String,
    targetHandle: String,
    label: String,
    animated: Boolean,
  },
  { _id: false }
);

const WorkflowSettingsSchema = new Schema<IWorkflowSettings>(
  {
    allowReentry: { type: Boolean, default: false },
    reentryCooldown: Number,
    timezone: { type: String, default: 'UTC' },
    notifyOnCompletion: { type: Boolean, default: false },
    notifyOnError: { type: Boolean, default: true },
    notificationEmails: [String],
    testMode: { type: Boolean, default: false },
    testContactId: String,
    platform: { type: String, enum: ['brevo', 'mailchimp', 'zoho'] },
  },
  { _id: false }
);

const WorkflowStatsSchema = new Schema<IWorkflowStats>(
  {
    totalInstances: { type: Number, default: 0 },
    activeInstances: { type: Number, default: 0 },
    completedInstances: { type: Number, default: 0 },
    exitedInstances: { type: Number, default: 0 },
    errorInstances: { type: Number, default: 0 },
    lastTriggeredAt: Date,
    averageCompletionTime: Number,
  },
  { _id: false }
);

const WebhookRegistrationSchema = new Schema<IWebhookRegistration>(
  {
    status: {
      type: String,
      enum: ['not_required', 'registered', 'failed'],
      default: 'not_required',
    },
    provider: String,
    webhookId: String,
    events: [String],
    error: String,
    updatedAt: Date,
  },
  { _id: false }
);

const AutomationWorkflowSchema = new Schema<IAutomationWorkflow>(
  {
    companyId: { type: String, required: true, index: true },
    createdById: { type: String, required: true },
    name: { type: String, required: true, maxlength: 200 },
    slug: { type: String, required: true, lowercase: true, trim: true },
    description: String,
    status: { type: String, enum: ['draft', 'active', 'paused', 'archived'], default: 'draft' },
    trigger: { type: WorkflowTriggerSchema, required: true },
    nodes: [WorkflowNodeSchema],
    edges: [WorkflowEdgeSchema],
    viewport: { x: { type: Number, default: 0 }, y: { type: Number, default: 0 }, zoom: { type: Number, default: 1 } },
    version: { type: Number, default: 1 },
    publishedAt: Date,
    publishedById: String,
    settings: { type: WorkflowSettingsSchema, default: {} },
    tags: [String],
    category: String,
    stats: { type: WorkflowStatsSchema, default: {} },
    webhookRegistration: { type: WebhookRegistrationSchema, default: undefined },
    deletedAt: Date,
  },
  { timestamps: true }
);

// Indexes for AutomationWorkflow
AutomationWorkflowSchema.index({ companyId: 1, status: 1 });
AutomationWorkflowSchema.index({ companyId: 1, slug: 1 }, { unique: true });
AutomationWorkflowSchema.index({ companyId: 1, 'trigger.type': 1 });
AutomationWorkflowSchema.index({ status: 1, 'trigger.type': 1 });

// Auto-generate slug from name
AutomationWorkflowSchema.pre('save', function (next) {
  if (!this.slug && this.name) {
    const base = this.name
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-|-$/g, '')
      .substring(0, 80);
    const suffix = Date.now().toString(36).slice(-4);
    this.slug = `${base}-${suffix}`;
  }
  next();
});

// Instance Schemas
const NodeExecutionStateSchema = new Schema<INodeExecutionState>(
  {
    nodeId: { type: String, required: true },
    status: { type: String, enum: ['pending', 'running', 'completed', 'skipped', 'error'], required: true },
    startedAt: Date,
    completedAt: Date,
    output: Schema.Types.Mixed,
    error: String,
  },
  { _id: false }
);

const InstanceErrorSchema = new Schema<IInstanceError>(
  {
    nodeId: { type: String, required: true },
    message: { type: String, required: true },
    timestamp: { type: Date, default: Date.now },
    retryCount: { type: Number, default: 0 },
  },
  { _id: false }
);

const AutomationInstanceSchema = new Schema<IAutomationInstance>(
  {
    companyId: { type: String, required: true, index: true },
    workflowId: { type: Schema.Types.ObjectId, ref: 'AutomationWorkflow', required: true },
    workflowVersion: { type: Number, required: true },
    contactId: { type: String, required: true, index: true },
    status: { type: String, enum: ['pending', 'running', 'paused', 'completed', 'exited', 'error'], default: 'pending', index: true },
    currentNodeId: { type: String, required: true },
    executedNodes: [String],
    nodeStates: { type: Map, of: NodeExecutionStateSchema },
    enteredAt: { type: Date, default: Date.now },
    lastProcessedAt: Date,
    completedAt: Date,
    exitReason: String,
    variables: Schema.Types.Mixed,
    executionErrors: [InstanceErrorSchema],
    scheduledFor: Date,
    waitingForEvent: String,
    goalReached: Boolean,
    goalReachedAt: Date,
  },
  { timestamps: true }
);

// Indexes for AutomationInstance
AutomationInstanceSchema.index({ companyId: 1, workflowId: 1, status: 1 });
AutomationInstanceSchema.index({ companyId: 1, contactId: 1 });
AutomationInstanceSchema.index({ status: 1, scheduledFor: 1 });
AutomationInstanceSchema.index({ waitingForEvent: 1 });

// Log Schema
const AutomationLogSchema = new Schema<IAutomationLog>(
  {
    companyId: { type: String, required: true, index: true },
    instanceId: { type: Schema.Types.ObjectId, ref: 'AutomationInstance', required: true },
    workflowId: { type: Schema.Types.ObjectId, ref: 'AutomationWorkflow', required: true },
    nodeId: { type: String, required: true },
    nodeType: { type: String, required: true },
    action: { type: String, required: true },
    status: { type: String, enum: ['started', 'completed', 'error', 'skipped'], required: true },
    input: Schema.Types.Mixed,
    output: Schema.Types.Mixed,
    error: String,
    timestamp: { type: Date, default: Date.now, index: true },
    duration: Number,
  },
  { timestamps: false }
);

// Indexes for AutomationLog
AutomationLogSchema.index({ companyId: 1, instanceId: 1 });
AutomationLogSchema.index({ companyId: 1, workflowId: 1, timestamp: -1 });
AutomationLogSchema.index({ instanceId: 1, nodeId: 1 });

// Export models
export const AutomationWorkflow = mongoose.models.AutomationWorkflow || mongoose.model('AutomationWorkflow', AutomationWorkflowSchema);
export const AutomationInstance = mongoose.models.AutomationInstance || mongoose.model('AutomationInstance', AutomationInstanceSchema);
export const AutomationLog = mongoose.models.AutomationLog || mongoose.model('AutomationLog', AutomationLogSchema);