import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AtlasRuntimeClient } from '../atlas-runtime.client';
import type { MessageChannel } from '../engine/types';
import type { MessageProvider, ProviderResult } from './message-provider';

type ProviderInput = Parameters<MessageProvider['send']>[0];

let dryRunSequence = 0;

function dryRunResult(channel: MessageChannel): ProviderResult {
  dryRunSequence += 1;
  return {
    success: true,
    providerMessageId: `dry_${Date.now()}_${dryRunSequence}`,
    status: 'dry_run',
    rawResponse: { channel, dryRun: true },
    retryable: false,
  };
}

abstract class BaseProvider implements MessageProvider {
  constructor(
    readonly channel: MessageChannel,
    protected readonly configService: ConfigService,
  ) {}

  async send(input: ProviderInput): Promise<ProviderResult> {
    if (input.dryRun || this.isDryRunEnabled()) {
      return dryRunResult(this.channel);
    }
    return this.sendReal(input);
  }

  protected isDryRunEnabled() {
    return (
      !isFalseFlag(this.configService.get('AUTOMATION_DRY_RUN')) ||
      !isTrueFlag(this.configService.get('AUTOMATION_SEND_ENABLED'))
    );
  }

  protected abstract sendReal(input: ProviderInput): Promise<ProviderResult>;
}

function isTrueFlag(value: unknown): boolean {
  return value === true || value === 'true';
}

function isFalseFlag(value: unknown): boolean {
  return value === false || value === 'false';
}

class AtlasDelegatedProvider extends BaseProvider {
  constructor(
    channel: MessageChannel,
    configService: ConfigService,
    private readonly atlasRuntime: AtlasRuntimeClient,
  ) {
    super(channel, configService);
  }

  protected sendReal(input: ProviderInput): Promise<ProviderResult> {
    return this.atlasRuntime.sendMessage({
      channel: this.channel,
      to: input.to,
      subject: input.subject,
      body: input.body,
      meta: input.meta,
      dryRun: false,
    });
  }
}

@Injectable()
export class MessageProviderRegistry {
  private readonly providers: Record<MessageChannel, MessageProvider>;

  constructor(configService: ConfigService, atlasRuntime: AtlasRuntimeClient) {
    this.providers = {
      EMAIL: new AtlasDelegatedProvider('EMAIL', configService, atlasRuntime),
      WHATSAPP: new AtlasDelegatedProvider(
        'WHATSAPP',
        configService,
        atlasRuntime,
      ),
      PUSH: new AtlasDelegatedProvider('PUSH', configService, atlasRuntime),
    };
  }

  getProvider(channel: MessageChannel): MessageProvider {
    return this.providers[channel];
  }
}
