/**
 * WhatsApp Message Service
 * Service for sending and managing WhatsApp messages
 *
 * @module WhatsApp
 */

import { Repository, FindOptionsWhere } from 'typeorm';
import { AppDataSource } from '../../../shared/database/typeorm.config';
import {
  WhatsAppMessage,
  MessageType,
  MessageStatus,
  MessageDirection,
} from '../entities';
import { ServiceContext } from './account.service';

export interface SendTextMessageDto {
  accountId: string;
  contactId: string;
  conversationId?: string;
  content: string;
  contextMessageId?: string;
}

export interface SendTemplateMessageDto {
  accountId: string;
  contactId: string;
  conversationId?: string;
  templateId: string;
  templateName: string;
  templateVariables?: string[];
}

export interface SendMediaMessageDto {
  accountId: string;
  contactId: string;
  conversationId?: string;
  messageType: 'image' | 'video' | 'audio' | 'document';
  mediaUrl: string;
  mediaMimeType?: string;
  caption?: string;
}

export interface SendInteractiveMessageDto {
  accountId: string;
  contactId: string;
  conversationId?: string;
  interactiveType: 'button' | 'list' | 'product' | 'product_list';
  interactiveData: Record<string, any>;
}

export interface ReceiveMessageDto {
  accountId: string;
  contactId: string;
  conversationId?: string;
  waMessageId: string;
  waConversationId?: string;
  messageType: MessageType;
  content?: string;
  caption?: string;
  mediaId?: string;
  mediaUrl?: string;
  mediaMimeType?: string;
  mediaSha256?: string;
  mediaSizeBytes?: number;
  contextMessageId?: string;
  metadata?: Record<string, any>;
}

export interface UpdateMessageStatusDto {
  status: MessageStatus;
  errorCode?: string;
  errorMessage?: string;
}

export interface MessageFilters {
  accountId?: string;
  contactId?: string;
  conversationId?: string;
  direction?: MessageDirection;
  messageType?: MessageType;
  status?: MessageStatus;
  dateFrom?: Date;
  dateTo?: Date;
}

export class WhatsAppMessageService {
  private repository: Repository<WhatsAppMessage>;

  constructor() {
    this.repository = AppDataSource.getRepository(WhatsAppMessage);
  }

  async findAll(
    ctx: ServiceContext,
    filters?: MessageFilters,
    pagination?: { page?: number; limit?: number }
  ): Promise<{ data: WhatsAppMessage[]; total: number }> {
    const where: FindOptionsWhere<WhatsAppMessage> = {
      tenantId: ctx.tenantId,
    };

    if (filters?.accountId) {
      where.accountId = filters.accountId;
    }
    if (filters?.contactId) {
      where.contactId = filters.contactId;
    }
    if (filters?.conversationId) {
      where.conversationId = filters.conversationId;
    }
    if (filters?.direction) {
      where.direction = filters.direction;
    }
    if (filters?.messageType) {
      where.messageType = filters.messageType;
    }
    if (filters?.status) {
      where.status = filters.status;
    }

    const page = pagination?.page || 1;
    const limit = pagination?.limit || 50;
    const skip = (page - 1) * limit;

    const [data, total] = await this.repository.findAndCount({
      where,
      relations: ['account', 'contact'],
      order: { createdAt: 'DESC' },
      skip,
      take: limit,
    });

    return { data, total };
  }

  async findById(ctx: ServiceContext, id: string): Promise<WhatsAppMessage | null> {
    return this.repository.findOne({
      where: { id, tenantId: ctx.tenantId },
      relations: ['account', 'contact'],
    });
  }

  async findByWaMessageId(ctx: ServiceContext, waMessageId: string): Promise<WhatsAppMessage | null> {
    return this.repository.findOne({
      where: { waMessageId, tenantId: ctx.tenantId },
    });
  }

  async findByConversation(
    ctx: ServiceContext,
    conversationId: string,
    pagination?: { page?: number; limit?: number }
  ): Promise<{ data: WhatsAppMessage[]; total: number }> {
    return this.findAll(ctx, { conversationId }, pagination);
  }

  async findByContact(
    ctx: ServiceContext,
    contactId: string,
    pagination?: { page?: number; limit?: number }
  ): Promise<{ data: WhatsAppMessage[]; total: number }> {
    return this.findAll(ctx, { contactId }, pagination);
  }

  async sendTextMessage(ctx: ServiceContext, data: SendTextMessageDto): Promise<WhatsAppMessage> {
    const message = this.repository.create({
      tenantId: ctx.tenantId,
      accountId: data.accountId,
      contactId: data.contactId,
      conversationId: data.conversationId,
      direction: 'outbound',
      messageType: 'text',
      content: data.content,
      contextMessageId: data.contextMessageId,
      status: 'pending',
    });

    return this.repository.save(message);
  }

  async sendTemplateMessage(ctx: ServiceContext, data: SendTemplateMessageDto): Promise<WhatsAppMessage> {
    const message = this.repository.create({
      tenantId: ctx.tenantId,
      accountId: data.accountId,
      contactId: data.contactId,
      conversationId: data.conversationId,
      direction: 'outbound',
      messageType: 'template',
      templateId: data.templateId,
      templateName: data.templateName,
      templateVariables: data.templateVariables || [],
      status: 'pending',
      isBillable: true,
    });

    return this.repository.save(message);
  }

  async sendMediaMessage(ctx: ServiceContext, data: SendMediaMessageDto): Promise<WhatsAppMessage> {
    const message = this.repository.create({
      tenantId: ctx.tenantId,
      accountId: data.accountId,
      contactId: data.contactId,
      conversationId: data.conversationId,
      direction: 'outbound',
      messageType: data.messageType,
      mediaUrl: data.mediaUrl,
      mediaMimeType: data.mediaMimeType,
      caption: data.caption,
      status: 'pending',
    });

    return this.repository.save(message);
  }

  async sendInteractiveMessage(ctx: ServiceContext, data: SendInteractiveMessageDto): Promise<WhatsAppMessage> {
    const message = this.repository.create({
      tenantId: ctx.tenantId,
      accountId: data.accountId,
      contactId: data.contactId,
      conversationId: data.conversationId,
      direction: 'outbound',
      messageType: 'interactive',
      interactiveType: data.interactiveType,
      interactiveData: data.interactiveData,
      status: 'pending',
    });

    return this.repository.save(message);
  }

  async receiveMessage(ctx: ServiceContext, data: ReceiveMessageDto): Promise<WhatsAppMessage> {
    const message = this.repository.create({
      tenantId: ctx.tenantId,
      accountId: data.accountId,
      contactId: data.contactId,
      conversationId: data.conversationId,
      waMessageId: data.waMessageId,
      waConversationId: data.waConversationId,
      direction: 'inbound',
      messageType: data.messageType,
      content: data.content,
      caption: data.caption,
      mediaId: data.mediaId,
      mediaUrl: data.mediaUrl,
      mediaMimeType: data.mediaMimeType,
      mediaSha256: data.mediaSha256,
      mediaSizeBytes: data.mediaSizeBytes,
      contextMessageId: data.contextMessageId,
      metadata: data.metadata,
      status: 'delivered',
    });

    return this.repository.save(message);
  }

  async updateStatus(
    ctx: ServiceContext,
    id: string,
    data: UpdateMessageStatusDto
  ): Promise<WhatsAppMessage | null> {
    const message = await this.findById(ctx, id);
    if (!message) {
      return null;
    }

    message.status = data.status;
    message.statusUpdatedAt = new Date();

    if (data.errorCode) {
      message.errorCode = data.errorCode;
    }
    if (data.errorMessage) {
      message.errorMessage = data.errorMessage;
    }

    switch (data.status) {
      case 'sent':
        message.sentAt = new Date();
        break;
      case 'delivered':
        message.deliveredAt = new Date();
        break;
      case 'read':
        message.readAt = new Date();
        break;
    }

    return this.repository.save(message);
  }

  async updateStatusByWaMessageId(
    ctx: ServiceContext,
    waMessageId: string,
    data: UpdateMessageStatusDto
  ): Promise<WhatsAppMessage | null> {
    const message = await this.findByWaMessageId(ctx, waMessageId);
    if (!message) {
      return null;
    }
    return this.updateStatus(ctx, message.id, data);
  }

  async markAsSent(ctx: ServiceContext, id: string, waMessageId: string): Promise<WhatsAppMessage | null> {
    const message = await this.findById(ctx, id);
    if (!message) {
      return null;
    }

    message.waMessageId = waMessageId;
    message.status = 'sent';
    message.sentAt = new Date();
    message.statusUpdatedAt = new Date();

    return this.repository.save(message);
  }

  async delete(ctx: ServiceContext, id: string): Promise<boolean> {
    const result = await this.repository.delete({ id, tenantId: ctx.tenantId });
    return result.affected ? result.affected > 0 : false;
  }

  async getStatistics(
    ctx: ServiceContext,
    accountId?: string,
    dateFrom?: Date,
    dateTo?: Date
  ): Promise<{
    totalSent: number;
    totalReceived: number;
    delivered: number;
    read: number;
    failed: number;
    pending: number;
    byType: Record<MessageType, number>;
  }> {
    const where: FindOptionsWhere<WhatsAppMessage> = { tenantId: ctx.tenantId };

    if (accountId) {
      where.accountId = accountId;
    }

    const messages = await this.repository.find({ where });

    const filteredMessages = messages.filter(m => {
      if (dateFrom && m.createdAt < dateFrom) return false;
      if (dateTo && m.createdAt > dateTo) return false;
      return true;
    });

    const byType: Record<string, number> = {};
    filteredMessages.forEach(m => {
      byType[m.messageType] = (byType[m.messageType] || 0) + 1;
    });

    return {
      totalSent: filteredMessages.filter(m => m.direction === 'outbound').length,
      totalReceived: filteredMessages.filter(m => m.direction === 'inbound').length,
      delivered: filteredMessages.filter(m => m.status === 'delivered').length,
      read: filteredMessages.filter(m => m.status === 'read').length,
      failed: filteredMessages.filter(m => m.status === 'failed').length,
      pending: filteredMessages.filter(m => m.status === 'pending').length,
      byType: byType as Record<MessageType, number>,
    };
  }

  async getRecentMessages(
    ctx: ServiceContext,
    contactId: string,
    limit: number = 20
  ): Promise<WhatsAppMessage[]> {
    return this.repository.find({
      where: { tenantId: ctx.tenantId, contactId },
      order: { createdAt: 'DESC' },
      take: limit,
    });
  }
}
