import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Cron, CronExpression } from '@nestjs/schedule';
import { NotificationEvent } from './entities/notification-event.entity';
import { WhatsappTemplate } from './entities/whatsapp-template.entity';
import { WhatsappMessageLog } from './entities/whatsapp-message-log.entity';

// Placeholder for User entity interface to avoid importing full Entity with relations
interface User {
  id: number;
  phone: string;
}

@Injectable()
export class WhatsAppSenderService {
  private readonly logger = new Logger(WhatsAppSenderService.name);
  private isProcessing = false;

  constructor(
    @InjectRepository(NotificationEvent)
    private notificationEventRepository: Repository<NotificationEvent>,
    @InjectRepository(WhatsappTemplate)
    private whatsappTemplateRepository: Repository<WhatsappTemplate>,
    @InjectRepository(WhatsappMessageLog)
    private whatsappMessageLogRepository: Repository<WhatsappMessageLog>,
  ) {}

  @Cron(CronExpression.EVERY_10_SECONDS)
  async handleCron() {
    if (this.isProcessing) return; // Prevent concurrent runs
    this.isProcessing = true;

    try {
      // this.logger.debug('Checking for pending WhatsApp notifications...');

      // 1. Fetch pending events
      const pendingEvents = await this.notificationEventRepository.find({
        where: { status: 'pending' },
        take: 10, // Process in batches
        order: { created_at: 'ASC' }, // Ensure oldest events are processed first
      });

      if (pendingEvents.length === 0) {
        // this.logger.debug('No pending notifications.'); // Keep this commented for less verbose logs if desired
        return;
      }

      this.logger.log(`Found ${pendingEvents.length} pending notifications.`);

      for (const event of pendingEvents) {
        try {
          await this.processEvent(event);
        } catch (error) {
          this.logger.error(`Failed to process event ${event.id}`, error.stack);
          // Mark event as failed if an unhandled error occurs during processing
          event.status = 'failed';
          event.processed_at = new Date();
          await this.notificationEventRepository.save(event);
          // Also log to WhatsappMessageLog for failed events
          const log = new WhatsappMessageLog();
          log.notification_event_id = event.id;
          log.phone = 'UNKNOWN'; // Phone might not be available if error occurred early
          log.status = 'failed';
          log.error_message = error.message;
          await this.whatsappMessageLogRepository.save(log);
        }
      }
    } catch (error) {
      this.logger.error('Error in WhatsApp sender loop', error);
    } finally {
      this.isProcessing = false;
    }
  }

  private async processEvent(event: NotificationEvent) {
    try {
      // 1. Fetch Template
      const template = await this.whatsappTemplateRepository.findOne({
        where: { id: event.template_id },
      });

      if (!template) {
        await this.failEvent(event, 'Template not found');
        return;
      }

      // 2. Fetch Recipient Phone (Manual Join using QueryBuilder)
      // Assuming 'users' table exists and has 'phone' column
      const userResult = await this.notificationEventRepository.manager
        .createQueryBuilder()
        .select('phone')
        .from('users', 'u')
        .where('u.id = :id', { id: event.recipient_user_id })
        .getRawOne();

      if (!userResult || !userResult.phone) {
        await this.failEvent(event, 'Recipient phone not found');
        return;
      }

      const recipientPhone = userResult.phone;

      // 3. Send Message (Mock Integration)
      const providerMsgId = await this.sendToProvider(
        recipientPhone,
        template,
        event.payload,
      );

      // 4. Log Success
      await this.logSuccess(event, recipientPhone, providerMsgId);
    } catch (error) {
      // Automatic retry logic could go here, for now just fail after 1 try or implement retry count check
      if (event.retry_count < 3) {
        event.retry_count++;
        await this.notificationEventRepository.save(event);
      } else {
        await this.failEvent(event, error.message || 'Unknown error');
      }
    }
  }

  // --- Mock Provider Integration ---
  private async sendToProvider(
    phone: string,
    template: WhatsappTemplate,
    variables: any,
  ): Promise<string> {
    // REAL IMPLEMENTATION WOULD GO HERE via axios/fetch
    // const body = { template: template.name, to: phone, components: ... }
    // await axios.post(...)

    this.logger.log(
      `[MOCK SEND] To: ${phone} | Template: ${template.name} | Vars: ${JSON.stringify(variables)}`,
    );

    // Simulate API call
    return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  private async logSuccess(
    event: NotificationEvent,
    phone: string,
    providerId: string,
  ) {
    // Update Event
    event.status = 'sent';
    event.processed_at = new Date();
    await this.notificationEventRepository.save(event);

    // Create Log
    const log = new WhatsappMessageLog();
    log.notification_event_id = event.id;
    log.phone = phone;
    log.provider_message_id = providerId;
    log.status = 'sent';
    await this.whatsappMessageLogRepository.save(log);
  }

  private async failEvent(event: NotificationEvent, errorMsg: string) {
    event.status = 'failed';
    event.processed_at = new Date();
    await this.notificationEventRepository.save(event);

    // Create Log (even for failures if we have a phone, but here we might fail getting phone)
    // If we failed getting phone, we can't log phone, but we can log error.
    const log = new WhatsappMessageLog();
    log.notification_event_id = event.id;
    log.phone = 'UNKNOWN'; // Or fetch logic if available
    log.status = 'failed';
    log.error_message = errorMsg;
    await this.whatsappMessageLogRepository.save(log);

    this.logger.error(`Event ${event.id} Failed: ${errorMsg}`);
  }
}
