import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AtlasProxyService } from '../atlas-proxy/atlas-proxy.service';
import type {
  AutomationChannel,
  AutomationLogStatus,
  AutomationRunStatus,
  AutomationStepStatus,
  PublishedAutomationDefinition,
  PublishedAutomationSummary,
} from './engine/types';
import type { ProviderResult } from './providers/message-provider';

export interface RuntimeSubject {
  subjectType?: string;
  subjectId?: string;
  contactId?: string;
  userId?: string;
  to?: string;
}

export interface CreateRunInput {
  automationId: string;
  versionId?: string | null;
  sourceEventId: string;
  subject: RuntimeSubject;
  payload: Record<string, unknown>;
  dryRun: boolean;
}

export interface RuntimeStepInput {
  runId: string;
  automationId: string;
  nodeKey: string;
  status: AutomationStepStatus;
  attempts: number;
  input?: Record<string, unknown>;
  output?: Record<string, unknown>;
  error?: string | null;
  metadata?: Record<string, unknown>;
  startedAt?: string | null;
  finishedAt?: string | null;
}

export interface RuntimeLogInput {
  automationId: string;
  versionId?: string | null;
  runId?: string | null;
  stepId?: string | null;
  contactId?: string | null;
  userId?: string | null;
  nodeKey?: string | null;
  blockLabel?: string | null;
  channel?: AutomationChannel | null;
  event: string;
  status: AutomationLogStatus;
  errorCode?: string | null;
  errorMessage?: string | null;
  providerResponse?: unknown;
  payloadSummary?: Record<string, unknown> | null;
  attempts?: number;
  nextRetryAt?: string | null;
  requestId?: string | null;
  dryRun: boolean;
}

export interface RuntimeEventInput {
  runId: string;
  runStatus?: AutomationRunStatus;
  finishedAt?: string | null;
  step?: RuntimeStepInput;
  log?: RuntimeLogInput;
}

export type IngestionEventStatus =
  | 'RECEIVED'
  | 'MATCHED'
  | 'ENQUEUED'
  | 'DUPLICATE'
  | 'FAILED'
  | 'DEGRADED';

export interface IngestionEventInput {
  eventName: string;
  source: string;
  subjectType?: string | null;
  subjectId?: string | null;
  contactId?: string | null;
  userId?: string | null;
  payload?: Record<string, unknown>;
  idempotencyKey: string;
  status: IngestionEventStatus;
  matched?: number;
  enqueued?: number;
  degraded?: boolean;
  duplicate?: boolean;
  errorCode?: string | null;
  errorMessage?: string | null;
  retryable?: boolean;
}

export interface RuntimeRunStatus {
  id: string;
  automationId: string;
  status: AutomationRunStatus;
  startedAt?: string | null;
  finishedAt?: string | null;
  dryRun: boolean;
}

@Injectable()
export class AtlasRuntimeClient {
  private readonly basePath: string;

  constructor(
    private readonly atlasProxy: AtlasProxyService,
    configService: ConfigService,
  ) {
    this.basePath =
      configService.get<string>('ATLAS_RUNTIME_CALLBACK_PATH') ||
      '/api/atlas/internal/automation-runtime';
  }

  getDefinition(id: string): Promise<PublishedAutomationDefinition> {
    return this.atlasProxy.forwardRequest<PublishedAutomationDefinition>(
      'GET',
      `${this.basePath}/definition/${id}`,
    );
  }

  async findPublishedByTrigger(
    trigger: string,
  ): Promise<PublishedAutomationSummary[]> {
    const response = await this.atlasProxy.forwardRequest<{
      data: PublishedAutomationSummary[];
    }>('GET', `${this.basePath}/by-trigger`, undefined, { trigger });
    return response.data;
  }

  async createRun(input: CreateRunInput) {
    const response = await this.atlasProxy.forwardRequest<{
      run: Record<string, unknown>;
    }>('POST', `${this.basePath}/events`, { run: input });
    return response.run;
  }

  async reportRuntimeEvent(input: RuntimeEventInput) {
    return this.atlasProxy.forwardRequest<{
      run?: Record<string, unknown>;
      step?: Record<string, unknown>;
      log?: Record<string, unknown>;
    }>('POST', `${this.basePath}/events`, input);
  }

  /** Pede ao Atlas para retomar um run pausado numa Espera (timer durável venceu). */
  async resumeRun(runId: string) {
    return this.atlasProxy.forwardRequest<{
      result?: Record<string, unknown>;
    }>('POST', `${this.basePath}/resume`, { runId });
  }

  async reportIngestionEvent(input: IngestionEventInput) {
    return this.atlasProxy.forwardRequest<{
      event?: Record<string, unknown>;
    }>('POST', `${this.basePath}/events`, { ingestionEvent: input });
  }

  async getRunStatus(runId: string): Promise<RuntimeRunStatus> {
    const response = await this.atlasProxy.forwardRequest<{
      run: RuntimeRunStatus;
    }>('POST', `${this.basePath}/events`, { runStatusCheck: { runId } });
    return response.run;
  }

  async checkOptOut(input: {
    contactId?: string | null;
    userId?: string | null;
    channel: AutomationChannel;
  }) {
    const response = await this.atlasProxy.forwardRequest<{ optOut: boolean }>(
      'POST',
      `${this.basePath}/events`,
      { optOutCheck: input },
    );
    return response.optOut;
  }

  async sendMessage(input: {
    channel: AutomationChannel;
    to: string;
    subject?: string;
    body: string;
    meta?: Record<string, unknown>;
    dryRun?: boolean;
  }): Promise<ProviderResult> {
    const response = await this.atlasProxy.forwardRequest<{
      result: ProviderResult;
    }>('POST', `${this.basePath}/send-message`, input);
    return response.result;
  }
}
