/* eslint-disable @typescript-eslint/no-unused-vars */
/**
 * Retention Campaign Engine - Automated intervention system
 * [4.1] Campaign triggers and personalized messaging
 * [4.2] Platform integrations (email/push/Slack)
 */

import { getRegisteredContainer } from '@bytelyst/cosmos';
import { bus } from '../../lib/event-bus.js';
import type {
  RetentionCampaignDoc,
  CreateCampaignInput,
  ChurnPredictionInput,
  UserChurnPredictionDoc,
} from './types.js';

export interface CampaignTriggerContext {
  userId: string;
  productId: string;
  churnProbability: number;
  riskSegment: string;
  topRiskFactors: Array<{ feature: string; description: string }>;
  suggestedActions: string[];
}

export interface CampaignDeliveryResult {
  success: boolean;
  channel: string;
  messageId?: string;
  error?: string;
  sentAt: string;
}

export class CampaignEngine {
  /**
   * Create a new retention campaign
   */
  async createCampaign(input: CreateCampaignInput): Promise<RetentionCampaignDoc> {
    const container = getRegisteredContainer('retention_campaigns');

    const doc: RetentionCampaignDoc = {
      id: `rc_${crypto.randomUUID()}`,
      ...input,
      status: 'draft',
      stats: {
        triggered: 0,
        sent: 0,
        opened: 0,
        clicked: 0,
        converted: 0,
        controlGroupSize: 0,
        controlChurnRate: 0,
        treatmentChurnRate: 0,
      },
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
      ttl: 365 * 24 * 60 * 60, // 1 year
    };

    await container.items.create(doc);
    return doc;
  }

  /**
   * Activate a campaign
   */
  async activateCampaign(campaignId: string): Promise<RetentionCampaignDoc | null> {
    const container = getRegisteredContainer('retention_campaigns');

    try {
      const { resource: doc } = await container.item(campaignId).read<RetentionCampaignDoc>();
      if (!doc) return null;

      doc.status = 'active';
      doc.updatedAt = new Date().toISOString();

      await container.item(campaignId).replace(doc);
      return doc;
    } catch {
      return null;
    }
  }

  /**
   * Trigger campaign for a user based on churn prediction
   */
  async triggerForUser(
    prediction: ChurnPredictionInput & {
      explanation: {
        topRiskFactors: Array<{ feature: string; description: string }>;
        suggestedActions: string[];
      };
    },
    testMode: boolean = false
  ): Promise<CampaignDeliveryResult[]> {
    const campaigns = await this.getActiveCampaignsForProduct(prediction.productId);
    const results: CampaignDeliveryResult[] = [];

    const context: CampaignTriggerContext = {
      userId: prediction.userId,
      productId: prediction.productId,
      churnProbability: prediction.churnProbability,
      riskSegment: prediction.riskSegment,
      topRiskFactors: prediction.explanation.topRiskFactors.slice(0, 3),
      suggestedActions: prediction.explanation.suggestedActions,
    };

    for (const campaign of campaigns) {
      // Check if user matches campaign conditions
      if (!this.matchesCampaignConditions(context, campaign)) {
        continue;
      }

      // Check frequency capping
      if (await this.isFrequencyCapped(context.userId, campaign)) {
        continue;
      }

      // Deliver messages
      for (const message of campaign.messages) {
        const result = await this.deliverMessage(context, message, testMode);
        results.push(result);

        if (result.success && !testMode) {
          await this.recordDelivery(campaign.id, context.userId, message.channel);
        }
      }

      // Emit event for tracking
      if (!testMode) {
        void bus.emit('predictive.campaign.triggered', {
          campaignId: campaign.id,
          userId: context.userId,
          productId: context.productId,
          riskSegment: context.riskSegment,
          channels: campaign.messages.map(m => m.channel),
        });
      }
    }

    return results;
  }

  /**
   * Manual trigger for testing
   */
  async manualTrigger(campaignId: string, testUserId: string): Promise<CampaignDeliveryResult[]> {
    const container = getRegisteredContainer('retention_campaigns');

    try {
      const { resource: campaign } = await container.item(campaignId).read<RetentionCampaignDoc>();
      if (!campaign) return [];

      const context: CampaignTriggerContext = {
        userId: testUserId,
        productId: campaign.productId,
        churnProbability: 0.75,
        riskSegment: 'high',
        topRiskFactors: [
          { feature: 'daysSinceLastSession', description: 'Session recency declined' },
        ],
        suggestedActions: ['Send re-engagement email'],
      };

      const results: CampaignDeliveryResult[] = [];

      for (const message of campaign.messages) {
        const result = await this.deliverMessage(context, message, true);
        results.push(result);
      }

      return results;
    } catch {
      return [];
    }
  }

  /**
   * Get active campaigns for a product
   */
  private async getActiveCampaignsForProduct(productId: string): Promise<RetentionCampaignDoc[]> {
    const container = getRegisteredContainer('retention_campaigns');

    const query = {
      query: 'SELECT * FROM c WHERE c.productId = @productId AND c.status = @status',
      parameters: [
        { name: '@productId', value: productId },
        { name: '@status', value: 'active' },
      ],
    };

    const { resources } = await container.items.query<RetentionCampaignDoc>(query).fetchAll();
    return resources;
  }

  /**
   * Check if user matches campaign conditions
   */
  private matchesCampaignConditions(
    context: CampaignTriggerContext,
    campaign: RetentionCampaignDoc
  ): boolean {
    // Check risk segment match
    if (
      campaign.audience.riskSegments?.length &&
      !campaign.audience.riskSegments.includes(context.riskSegment)
    ) {
      return false;
    }

    // Check trigger conditions
    for (const condition of campaign.trigger.conditions) {
      const value = this.getContextValue(context, condition.field);

      switch (condition.operator) {
        case 'gt':
          if (!(Number(value) > (condition.value as number))) return false;
          break;
        case 'lt':
          if (!(Number(value) < (condition.value as number))) return false;
          break;
        case 'eq':
          if (String(value) !== String(condition.value)) return false;
          break;
        case 'in':
          if (!(condition.value as unknown[]).includes(value)) return false;
          break;
      }
    }

    return true;
  }

  /**
   * Get value from context by field path
   */
  private getContextValue(context: CampaignTriggerContext, field: string): unknown {
    const parts = field.split('.');
    let value: unknown = context;

    for (const part of parts) {
      if (value && typeof value === 'object') {
        value = (value as Record<string, unknown>)[part];
      } else {
        return undefined;
      }
    }

    return value;
  }

  /**
   * Check if user is frequency capped
   */
  private async isFrequencyCapped(
    userId: string,
    campaign: RetentionCampaignDoc
  ): Promise<boolean> {
    if (!campaign.audience.excludeRecentContact) return false;

    const container = getRegisteredContainer('campaign_deliveries');
    const hoursAgo = new Date();
    hoursAgo.setHours(hoursAgo.getHours() - campaign.audience.excludeRecentContact);

    const query = {
      query: 'SELECT VALUE COUNT(1) FROM c WHERE c.userId = @userId AND c.sentAt >= @cutoff',
      parameters: [
        { name: '@userId', value: userId },
        { name: '@cutoff', value: hoursAgo.toISOString() },
      ],
    };

    try {
      const { resources } = await container.items.query<number>(query).fetchAll();
      return (resources[0] || 0) > 0;
    } catch {
      return false;
    }
  }

  /**
   * Deliver message through appropriate channel
   */
  private async deliverMessage(
    context: CampaignTriggerContext,
    message: { channel: string; templateId: string; variant?: string; delayHours?: number },
    testMode: boolean
  ): Promise<CampaignDeliveryResult> {
    const sentAt = new Date().toISOString();

    // Simulate delay
    if (message.delayHours && !testMode) {
      // In production, this would schedule for later delivery
    }

    switch (message.channel) {
      case 'email':
        return this.deliverEmail(context, message.templateId, testMode, sentAt);
      case 'push':
        return this.deliverPush(context, message.templateId, testMode, sentAt);
      case 'in_app':
        return this.deliverInApp(context, message.templateId, testMode, sentAt);
      case 'slack_cs':
        return this.deliverSlackCS(context, message.templateId, testMode, sentAt);
      default:
        return {
          success: false,
          channel: message.channel,
          error: 'Unknown channel',
          sentAt,
        };
    }
  }

  /**
   * Deliver email via delivery module
   */
  private async deliverEmail(
    context: CampaignTriggerContext,
    templateId: string,
    testMode: boolean,
    sentAt: string
  ): Promise<CampaignDeliveryResult> {
    if (testMode) {
      return {
        success: true,
        channel: 'email',
        messageId: `test_${crypto.randomUUID()}`,
        sentAt,
      };
    }

    try {
      // In production, call delivery module
      // await deliveryService.sendEmail({...})

      void bus.emit('delivery.email.requested', {
        userId: context.userId,
        productId: context.productId,
        templateId,
        context: {
          churnProbability: context.churnProbability,
          riskSegment: context.riskSegment,
          suggestedActions: context.suggestedActions,
        },
      });

      return {
        success: true,
        channel: 'email',
        messageId: `email_${crypto.randomUUID()}`,
        sentAt,
      };
    } catch (error) {
      return {
        success: false,
        channel: 'email',
        error: error instanceof Error ? error.message : 'Email delivery failed',
        sentAt,
      };
    }
  }

  /**
   * Deliver push notification
   */
  private async deliverPush(
    context: CampaignTriggerContext,
    templateId: string,
    testMode: boolean,
    sentAt: string
  ): Promise<CampaignDeliveryResult> {
    if (testMode) {
      return {
        success: true,
        channel: 'push',
        messageId: `test_push_${crypto.randomUUID()}`,
        sentAt,
      };
    }

    void bus.emit('notifications.push.requested', {
      userId: context.userId,
      productId: context.productId,
      title: 'We miss you!',
      body: 'Come back and explore new features.',
      data: { campaign: 'retention', riskSegment: context.riskSegment },
    });

    return {
      success: true,
      channel: 'push',
      messageId: `push_${crypto.randomUUID()}`,
      sentAt,
    };
  }

  /**
   * Deliver in-app message
   */
  private async deliverInApp(
    context: CampaignTriggerContext,
    templateId: string,
    testMode: boolean,
    sentAt: string
  ): Promise<CampaignDeliveryResult> {
    if (testMode) {
      return {
        success: true,
        channel: 'in_app',
        messageId: `test_inapp_${crypto.randomUUID()}`,
        sentAt,
      };
    }

    void bus.emit('notifications.inapp.create', {
      userId: context.userId,
      productId: context.productId,
      title: 'Personalized for you',
      content: 'Based on your interests, check out these features.',
      priority: context.riskSegment === 'critical' ? 'high' : 'normal',
    });

    return {
      success: true,
      channel: 'in_app',
      messageId: `inapp_${crypto.randomUUID()}`,
      sentAt,
    };
  }

  /**
   * Deliver Slack notification to CS team
   */
  private async deliverSlackCS(
    context: CampaignTriggerContext,
    templateId: string,
    testMode: boolean,
    sentAt: string
  ): Promise<CampaignDeliveryResult> {
    if (testMode) {
      return {
        success: true,
        channel: 'slack_cs',
        messageId: `test_slack_${crypto.randomUUID()}`,
        sentAt,
      };
    }

    const message = {
      text: `🚨 High Risk User Alert`,
      blocks: [
        {
          type: 'section',
          text: {
            type: 'mrkdwn',
            text: `*High Risk User Detected*\nUser: ${context.userId}\nProduct: ${context.productId}\nChurn Probability: ${Math.round(context.churnProbability * 100)}%\nRisk Segment: ${context.riskSegment}`,
          },
        },
        {
          type: 'section',
          text: {
            type: 'mrkdwn',
            text: `*Top Risk Factors:*\n${context.topRiskFactors.map(f => `- ${f.description}`).join('\n')}`,
          },
        },
        {
          type: 'section',
          text: {
            type: 'mrkdwn',
            text: `*Suggested Actions:*\n${context.suggestedActions.map(a => `- ${a}`).join('\n')}`,
          },
        },
      ],
    };

    void bus.emit('integrations.slack.notify', {
      channel: '#customer-success',
      message,
    });

    return {
      success: true,
      channel: 'slack_cs',
      messageId: `slack_${crypto.randomUUID()}`,
      sentAt,
    };
  }

  /**
   * Record campaign delivery
   */
  private async recordDelivery(campaignId: string, userId: string, channel: string): Promise<void> {
    const container = getRegisteredContainer('campaign_deliveries');

    await container.items.create({
      id: `cd_${crypto.randomUUID()}`,
      campaignId,
      userId,
      channel,
      sentAt: new Date().toISOString(),
      openedAt: null,
      clickedAt: null,
      convertedAt: null,
      ttl: 90 * 24 * 60 * 60,
    });
  }

  /**
   * Get campaign statistics
   */
  async getCampaignStats(campaignId: string): Promise<{
    triggered: number;
    sent: number;
    opened: number;
    clicked: number;
    converted: number;
    conversionRate: number;
  } | null> {
    const container = getRegisteredContainer('campaign_deliveries');

    const query = {
      query: 'SELECT * FROM c WHERE c.campaignId = @campaignId',
      parameters: [{ name: '@campaignId', value: campaignId }],
    };

    try {
      const { resources } = await container.items.query(query).fetchAll();

      const sent = resources.length;
      const opened = resources.filter(r => r.openedAt).length;
      const clicked = resources.filter(r => r.clickedAt).length;
      const converted = resources.filter(r => r.convertedAt).length;

      return {
        triggered: sent,
        sent,
        opened,
        clicked,
        converted,
        conversionRate: sent > 0 ? converted / sent : 0,
      };
    } catch {
      return null;
    }
  }
}

export const campaignEngine = new CampaignEngine();
