import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { Connection, Client, WorkflowClient } from '@temporalio/client';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class TemporalService implements OnModuleInit {
  private readonly logger = new Logger(TemporalService.name);
  private client: WorkflowClient;
  private connection: Connection;

  constructor(private readonly configService: ConfigService) {}

  async onModuleInit() {
    // 在测试环境下跳过 Temporal 连接
    if (process.env.NODE_ENV === 'test' || process.env.SKIP_TEMPORAL === 'true') {
      this.logger.log('Skipping Temporal connection (test mode)');
      return;
    }

    const temporalAddress = this.configService.get<string>('TEMPORAL_ADDRESS', 'localhost:7233');
    const namespace = this.configService.get<string>('TEMPORAL_NAMESPACE', 'default');
    const isDevelopment = process.env.NODE_ENV === 'development';

    this.logger.log(`Connecting to Temporal at ${temporalAddress}, namespace: ${namespace}`);

    try {
      // 添加连接超时（10秒）
      const connectPromise = Connection.connect({
        address: temporalAddress,
      });
      
      const timeoutPromise = new Promise<never>((_, reject) => {
        setTimeout(() => reject(new Error('Temporal connection timeout (10s)')), 10000);
      });

      this.connection = await Promise.race([connectPromise, timeoutPromise]);

      this.client = new WorkflowClient({
        connection: this.connection,
        namespace,
      });

      this.logger.log('✅ Temporal client connected successfully');
    } catch (error) {
      const errorMessage = `❌ Failed to connect to Temporal: ${error.message}`;
      this.logger.error(errorMessage);
      
      // ⭐ 生产环境必须连接成功，否则抛出异常导致启动失败
      if (!isDevelopment) {
        this.logger.error('🚨 Temporal connection is REQUIRED in production. Application startup failed.');
        throw new Error(`Temporal connection failed: ${error.message}`);
      }
      
      // 开发环境允许继续启动，但给出明显警告
      this.logger.warn('⚠️  Temporal is not available. Workflow features will be DISABLED.');
      this.logger.warn('💡 To enable workflows, start Temporal:');
      this.logger.warn('   docker-compose up -d temporal');
      this.logger.warn('   or check TEMPORAL_ADDRESS environment variable');
    }
  }

  async startApprovalWorkflow(params: {
    instanceId: string;
    workflowId: string;  // 添加 workflowId 参数
    processModel: any;
    settings: any;
    variables: Record<string, any>;
    initiatorId: string;
    businessType: string;
    businessId: string;
    callbackUrl?: string;
  }): Promise<{ runId: string }> {
    if (!this.client) {
      const isDevelopment = process.env.NODE_ENV === 'development';
      
      if (!isDevelopment) {
        // 生产环境必须有 Temporal 客户端
        throw new Error('❌ Temporal client is not available. Cannot start workflow in production.');
      }
      
      // 开发环境允许使用 mock
      this.logger.warn('⚠️  Temporal client not available, using mock workflow');
      return { runId: `mock-${Date.now()}` };
    }

    const workflowId = params.workflowId;  // 使用传入的 workflowId
    const taskQueue = this.configService.get<string>('temporal.taskQueue', 'ffoa-task-queue');

    try {
      const handle = await this.client.start('genericApprovalWorkflow', {
        taskQueue,
        workflowId,
        args: [params],
      });

      this.logger.log(`✅ Started workflow: ${workflowId}, runId: ${handle.firstExecutionRunId}`);

      return { runId: handle.firstExecutionRunId };
    } catch (error) {
      this.logger.error(`❌ Failed to start workflow: ${error.message}`);
      throw error;
    }
  }

  async sendSignal(workflowId: string, signalName: string, data: any): Promise<void> {
    if (!this.client) {
      const isDevelopment = process.env.NODE_ENV === 'development';
      
      if (!isDevelopment) {
        throw new Error('❌ Temporal client is not available. Cannot send signal in production.');
      }
      
      this.logger.warn(`⚠️  Temporal client not available, signal ${signalName} not sent (mock mode)`);
      return;
    }

    try {
      const handle = this.client.getHandle(workflowId);
      await handle.signal(signalName, data);
      this.logger.log(`Sent signal ${signalName} to workflow ${workflowId}`);
    } catch (error) {
      this.logger.error(`Failed to send signal: ${error}`);
      throw error;
    }
  }

  async queryWorkflow(workflowId: string, queryName: string): Promise<any> {
    if (!this.client) {
      this.logger.warn(`Temporal client not available, query ${queryName} not executed`);
      return null;
    }

    try {
      const handle = this.client.getHandle(workflowId);
      const result = await handle.query(queryName);
      return result;
    } catch (error) {
      this.logger.error(`Failed to query workflow: ${error}`);
      throw error;
    }
  }

  async terminateWorkflow(workflowId: string, reason: string): Promise<void> {
    if (!this.client) {
      this.logger.warn(`Temporal client not available, workflow ${workflowId} not terminated`);
      return;
    }

    try {
      const handle = this.client.getHandle(workflowId);
      await handle.terminate(reason);
      this.logger.log(`Terminated workflow ${workflowId}: ${reason}`);
    } catch (error) {
      this.logger.error(`Failed to terminate workflow: ${error}`);
      throw error;
    }
  }

  async cancelWorkflow(workflowId: string): Promise<void> {
    if (!this.client) {
      this.logger.warn(`Temporal client not available, workflow ${workflowId} not cancelled`);
      return;
    }

    try {
      const handle = this.client.getHandle(workflowId);
      await handle.cancel();
      this.logger.log(`Cancelled workflow ${workflowId}`);
    } catch (error) {
      this.logger.error(`Failed to cancel workflow: ${error}`);
      throw error;
    }
  }

  async getWorkflowStatus(workflowId: string): Promise<string | null> {
    if (!this.client) {
      return null;
    }

    try {
      const handle = this.client.getHandle(workflowId);
      const description = await handle.describe();
      return description.status.name;
    } catch (error) {
      this.logger.error(`Failed to get workflow status: ${error}`);
      return null;
    }
  }
}

