import type {
  Channel,
  NormalizedMessage,
  ResolvedCredentials,
  ProviderErrorCode,
} from '@zyphon/shared-types';
import type {
  ProviderAdapter,
  ProviderResult,
  ProviderHealth,
  WebhookRequest,
  DeliveryEvent,
} from '@zyphon/provider-contracts';

export interface MockAdapterOptions {
  id: string;
  channel: Channel;
  latencyMs?: number;
  shouldFail?: boolean;
  failErrorCode?: ProviderErrorCode;
  failMessage?: string;
}

export class MockProviderAdapter implements ProviderAdapter {
  public readonly id: string;
  public readonly channel: Channel;
  public latencyMs: number;
  public shouldFail: boolean;
  public failErrorCode: ProviderErrorCode;
  public failMessage: string;
  public sentMessages: NormalizedMessage[] = [];

  constructor(options: MockAdapterOptions) {
    this.id = options.id;
    this.channel = options.channel;
    this.latencyMs = options.latencyMs ?? 10;
    this.shouldFail = options.shouldFail ?? false;
    this.failErrorCode = options.failErrorCode ?? 'PROVIDER_5XX';
    this.failMessage = options.failMessage ?? 'Mock provider simulated failure';
  }

  public async validateConfiguration(_c: ResolvedCredentials): Promise<void> {
    // Valid by default
  }

  public async send(
    m: NormalizedMessage,
    _c: ResolvedCredentials,
    signal: AbortSignal
  ): Promise<ProviderResult> {
    if (signal.aborted) {
      return {
        success: false,
        error: {
          code: 'TIMEOUT',
          message: 'Operation timed out',
        },
      };
    }

    if (this.latencyMs > 0) {
      await new Promise((resolve) => setTimeout(resolve, this.latencyMs));
    }

    if (this.shouldFail) {
      return {
        success: false,
        error: {
          code: this.failErrorCode,
          message: this.failMessage,
        },
      };
    }

    this.sentMessages.push(m);
    return {
      success: true,
      provider_reference: `mock_ref_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`,
      raw_response: {
        mock: true,
        channel: this.channel,
      },
    };
  }

  public async healthCheck(_c: ResolvedCredentials): Promise<ProviderHealth> {
    return {
      status: this.shouldFail ? 'down' : 'healthy',
      latency_ms: this.latencyMs,
      checked_at: Date.now(),
      message: this.shouldFail ? this.failMessage : 'Mock provider is operational',
    };
  }

  public parseWebhook(req: WebhookRequest): DeliveryEvent | null {
    const body = req.body as any;
    if (body?.message_id && body?.status) {
      return {
        message_id: body.message_id,
        status: body.status === 'delivered' ? 'delivered' : 'undelivered',
        timestamp: Date.now(),
        provider: this.id,
        raw: body,
      };
    }
    return null;
  }
}

