import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, In } from 'typeorm';
import { NotificationEvent } from '../../modules/notifications/entities/notification-event.entity';
import { WhatsappTemplate } from '../../modules/notifications/entities/whatsapp-template.entity';

@Injectable()
export class MobileNotificationsService implements OnModuleInit {
  private readonly logger = new Logger(MobileNotificationsService.name);

  constructor(
    @InjectRepository(NotificationEvent)
    private readonly eventRepository: Repository<NotificationEvent>,
    @InjectRepository(WhatsappTemplate)
    private readonly templateRepository: Repository<WhatsappTemplate>,
  ) {}

  async onModuleInit() {
    this.logger.log('Initializing MobileNotificationsService and checking templates seed...');
    await this.seedTemplates();
  }

  private async seedTemplates() {
    try {
      const { MOBILE_NOTIFICATION_TEMPLATES } = await import('./mobile-notification-templates');
      
      for (const t of MOBILE_NOTIFICATION_TEMPLATES) {
        const existing = await this.templateRepository.findOne({
          where: { name: t.name },
        });

        if (!existing) {
          this.logger.log(`Seeding template: '${t.name}'`);
          const newTemplate = this.templateRepository.create({
            name: t.name,
            body: t.body,
            variables: t.variables,
            language_code: t.language_code,
            category: t.category,
            recipient: t.recipient,
            is_active: true,
          });
          await this.templateRepository.save(newTemplate);
        } else {
          if (existing.body !== t.body || existing.variables !== t.variables) {
            this.logger.log(`Updating template: '${t.name}'`);
            existing.body = t.body;
            existing.variables = t.variables;
            await this.templateRepository.save(existing);
          }
        }
      }
      this.logger.log('Mobile notification templates seed check complete.');
    } catch (error) {
      this.logger.error('Failed to seed mobile notification templates:', error);
    }
  }

  /**
   * Helper to format human-readable relative time (e.g. "3 hours ago").
   */
  private getTimeAgoString(createdAt: any): string {
    const createdDate = createdAt ? new Date(createdAt) : null;
    const now = new Date();

    if (!createdDate || Number.isNaN(createdDate.getTime())) {
      return '';
    }

    const diffMs = now.getTime() - createdDate.getTime();
    if (diffMs < 0) return 'just now';

    const minutes = Math.floor(diffMs / (60 * 1000));
    if (minutes < 1) return 'just now';
    if (minutes < 60) return `${minutes} minutes ago`;

    const hours = Math.floor(minutes / 60);
    if (hours < 24) return `${hours} hours ago`;

    const days = Math.floor(hours / 24);
    if (days < 30) return `${days} days ago`;

    const months = Math.floor(days / 30);
    if (months < 12) return `${months} months ago`;

    const years = Math.floor(months / 12);
    return `${years} years ago`;
  }

  /**
   * Replaces template placeholders (e.g. {{1}}, {1}) with value from payload.
   */
  private formatMessage(body: string, payload: any): string {
    if (!body) return '';
    if (!payload) return body;

    let formatted = body;
    let parsedPayload = payload;

    if (typeof payload === 'string') {
      try {
        parsedPayload = JSON.parse(payload);
      } catch (e) {
        parsedPayload = {};
      }
    }

    for (const key of Object.keys(parsedPayload)) {
      const value = parsedPayload[key] !== null && parsedPayload[key] !== undefined 
        ? String(parsedPayload[key]) 
        : '—';
      const placeholderRegexDouble = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
      const placeholderRegexSingle = new RegExp(`\\{${key}\\}`, 'g');
      formatted = formatted
        .replace(placeholderRegexDouble, value)
        .replace(placeholderRegexSingle, value);
    }
    return formatted;
  }

  /**
   * Retrieve paginated and resolved notifications list for a specific recipient user.
   */
  async getNotifications(options: {
    userId: number;
    page: number;
    limit: number;
    status?: string;
  }) {
    const { userId, page, limit, status } = options;
    const offset = (page - 1) * limit;

    // 1. Build Query for notifications of this user
    const queryBuilder = this.eventRepository
      .createQueryBuilder('event')
      .where('event.recipient_user_id = :userId', { userId })
      .orderBy('event.created_at', 'DESC')
      .skip(offset)
      .take(limit);

    if (status) {
      queryBuilder.andWhere('event.status = :status', { status });
    }

    // 2. Fetch data & total count
    const [events, total] = await queryBuilder.getManyAndCount();

    // 3. Resolve template details for notifications in parallel
    const templateIds = Array.from(new Set(events.map((e) => e.template_id).filter(Boolean)));
    let templatesMap = new Map<number, WhatsappTemplate>();

    if (templateIds.length > 0) {
      const templates = await this.templateRepository.find({
        where: { id: In(templateIds) },
      });
      templatesMap = new Map(templates.map((t) => [t.id, t]));
    }

    // 4. Transform notification data to format the payload body
    const notifications = events.map((event) => {
      const template = templatesMap.get(event.template_id);
      const rawBody = template ? template.body : '';
      const formattedBody = this.formatMessage(rawBody, event.payload);

      // Map reference type / template name to a user-friendly title
      let title = 'Notification';
      if (template?.name === 'candidate_profile_viewed') {
        title = 'Profile Viewed';
      } else if (template?.name === 'candidate_profile_completion_reminder') {
        title = 'Complete Your Profile';
      } else if (template?.name === 'candidate_ai_feedback_ready') {
        title = 'AI Feedback Ready';
      } else if (template?.name === 'candidate_resume_review_tip') {
        title = 'Resume Writing Tip';
      } else if (template?.name === 'seeker_registration_success') {
        title = 'Welcome to Jobvumi';
      } else if (template?.name === 'candidate_job_applied_confirmation') {
        title = 'Application Submitted';
      } else if (event.reference_type === 'job_application') {
        title = 'Job Application Update';
      } else if (event.reference_type === 'job_post') {
        title = 'New Job Match';
      } else if (event.reference_type === 'company') {
        title = 'Company Update';
      } else if (template?.name) {
        // Fallback: title-case the template name
        title = template.name
          .split('_')
          .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
          .join(' ');
      }

      return {
        id: Number(event.id),
        template_id: event.template_id,
        template_name: template ? template.name : null,
        recipient_user_id: Number(event.recipient_user_id),
        reference_type: event.reference_type,
        reference_id: event.reference_id,
        title,
        body: formattedBody,
        payload: event.payload,
        status: event.status,
        is_read: event.is_read,
        created_at: event.created_at,
        processed_at: event.processed_at,
        time_ago: this.getTimeAgoString(event.created_at),
      };
    });

    return {
      success: true,
      notifications,
      pagination: {
        page,
        limit,
        total,
        totalPages: Math.ceil(total / limit),
      },
    };
  }

  /**
   * Mark a single notification as read for a user.
   */
  async markAsRead(notificationId: number, userId: number): Promise<boolean> {
    const event = await this.eventRepository.findOne({
      where: { id: notificationId, recipient_user_id: userId },
    });

    if (!event) {
      return false;
    }

    event.is_read = 1;
    await this.eventRepository.save(event);
    return true;
  }

  /**
   * Mark all notifications as read for a user.
   */
  async markAllAsRead(userId: number): Promise<boolean> {
    await this.eventRepository.update(
      { recipient_user_id: userId, is_read: 0 },
      { is_read: 1 },
    );
    return true;
  }

  /**
   * Get the count of unread notifications for a user.
   */
  async getUnreadCount(userId: number): Promise<number> {
    return this.eventRepository.count({
      where: { recipient_user_id: userId, is_read: 0 },
    });
  }
}
