/**
 * WhatsApp Contact Service
 * Service for managing WhatsApp contacts
 *
 * @module WhatsApp
 */

import { Repository, FindOptionsWhere } from 'typeorm';
import { AppDataSource } from '../../../shared/database/typeorm.config';
import { WhatsAppContact, ConversationStatus } from '../entities';
import { ServiceContext } from './account.service';

export interface CreateContactDto {
  accountId: string;
  phoneNumber: string;
  waId?: string;
  profileName?: string;
  profilePictureUrl?: string;
  customerId?: string;
  userId?: string;
  tags?: string[];
  notes?: string;
}

export interface UpdateContactDto {
  profileName?: string;
  profilePictureUrl?: string;
  customerId?: string;
  userId?: string;
  conversationStatus?: ConversationStatus;
  optedIn?: boolean;
  optedOut?: boolean;
  tags?: string[];
  notes?: string;
}

export interface ContactFilters {
  accountId?: string;
  conversationStatus?: ConversationStatus;
  optedIn?: boolean;
  optedOut?: boolean;
  tag?: string;
  search?: string;
}

export interface PaginationOptions {
  page?: number;
  limit?: number;
}

export class WhatsAppContactService {
  private repository: Repository<WhatsAppContact>;

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

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

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

    if (filters?.conversationStatus) {
      where.conversationStatus = filters.conversationStatus;
    }

    if (filters?.optedIn !== undefined) {
      where.optedIn = filters.optedIn;
    }

    if (filters?.optedOut !== undefined) {
      where.optedOut = filters.optedOut;
    }

    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'],
      order: { lastMessageAt: 'DESC' },
      skip,
      take: limit,
    });

    return { data, total };
  }

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

  async findByPhoneNumber(
    ctx: ServiceContext,
    accountId: string,
    phoneNumber: string
  ): Promise<WhatsAppContact | null> {
    return this.repository.findOne({
      where: { accountId, phoneNumber, tenantId: ctx.tenantId },
    });
  }

  async findByWaId(ctx: ServiceContext, accountId: string, waId: string): Promise<WhatsAppContact | null> {
    return this.repository.findOne({
      where: { accountId, waId, tenantId: ctx.tenantId },
    });
  }

  async findByTag(ctx: ServiceContext, tag: string): Promise<WhatsAppContact[]> {
    const contacts = await this.repository.find({
      where: { tenantId: ctx.tenantId },
    });
    return contacts.filter(c => c.tags.includes(tag));
  }

  async findOptedIn(ctx: ServiceContext, accountId?: string): Promise<WhatsAppContact[]> {
    const where: FindOptionsWhere<WhatsAppContact> = {
      tenantId: ctx.tenantId,
      optedIn: true,
      optedOut: false,
    };

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

    return this.repository.find({
      where,
      order: { profileName: 'ASC' },
    });
  }

  async create(ctx: ServiceContext, data: CreateContactDto): Promise<WhatsAppContact> {
    const contact = this.repository.create({
      ...data,
      tenantId: ctx.tenantId,
    });
    return this.repository.save(contact);
  }

  async upsertByPhoneNumber(ctx: ServiceContext, data: CreateContactDto): Promise<WhatsAppContact> {
    const existing = await this.findByPhoneNumber(ctx, data.accountId, data.phoneNumber);
    if (existing) {
      Object.assign(existing, {
        waId: data.waId ?? existing.waId,
        profileName: data.profileName ?? existing.profileName,
        profilePictureUrl: data.profilePictureUrl ?? existing.profilePictureUrl,
      });
      return this.repository.save(existing);
    }
    return this.create(ctx, data);
  }

  async update(ctx: ServiceContext, id: string, data: UpdateContactDto): Promise<WhatsAppContact | null> {
    const contact = await this.findById(ctx, id);
    if (!contact) {
      return null;
    }

    if (data.optedIn === true) {
      contact.optedInAt = new Date();
    }
    if (data.optedOut === true) {
      contact.optedOutAt = new Date();
    }

    Object.assign(contact, data);
    return this.repository.save(contact);
  }

  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 addTag(ctx: ServiceContext, id: string, tag: string): Promise<WhatsAppContact | null> {
    const contact = await this.findById(ctx, id);
    if (!contact) {
      return null;
    }

    if (!contact.tags.includes(tag)) {
      contact.tags = [...contact.tags, tag];
      return this.repository.save(contact);
    }
    return contact;
  }

  async removeTag(ctx: ServiceContext, id: string, tag: string): Promise<WhatsAppContact | null> {
    const contact = await this.findById(ctx, id);
    if (!contact) {
      return null;
    }

    contact.tags = contact.tags.filter(t => t !== tag);
    return this.repository.save(contact);
  }

  async optIn(ctx: ServiceContext, id: string): Promise<WhatsAppContact | null> {
    return this.update(ctx, id, { optedIn: true, optedOut: false });
  }

  async optOut(ctx: ServiceContext, id: string): Promise<WhatsAppContact | null> {
    return this.update(ctx, id, { optedOut: true });
  }

  async updateLastMessage(
    ctx: ServiceContext,
    id: string,
    direction: 'inbound' | 'outbound'
  ): Promise<void> {
    const now = new Date();
    const windowExpiration = new Date(now.getTime() + 24 * 60 * 60 * 1000); // 24 hours

    const updateData: Partial<WhatsAppContact> = {
      lastMessageAt: now,
      lastMessageDirection: direction,
    };

    if (direction === 'inbound') {
      updateData.conversationWindowExpiresAt = windowExpiration;
      updateData.canSendTemplateOnly = false;
    }

    await this.repository.update(
      { id, tenantId: ctx.tenantId },
      updateData
    );

    if (direction === 'inbound') {
      await this.repository.increment({ id, tenantId: ctx.tenantId }, 'totalMessagesReceived', 1);
    } else {
      await this.repository.increment({ id, tenantId: ctx.tenantId }, 'totalMessagesSent', 1);
    }
  }

  async checkConversationWindow(ctx: ServiceContext, id: string): Promise<boolean> {
    const contact = await this.findById(ctx, id);
    if (!contact) {
      return false;
    }

    if (!contact.conversationWindowExpiresAt) {
      return false;
    }

    const isOpen = contact.conversationWindowExpiresAt > new Date();
    if (!isOpen && !contact.canSendTemplateOnly) {
      await this.repository.update(
        { id, tenantId: ctx.tenantId },
        { canSendTemplateOnly: true }
      );
    }

    return isOpen;
  }

  async getStatistics(ctx: ServiceContext, accountId?: string): Promise<{
    total: number;
    optedIn: number;
    optedOut: number;
    active: number;
    waiting: number;
    resolved: number;
    blocked: number;
  }> {
    const where: FindOptionsWhere<WhatsAppContact> = { tenantId: ctx.tenantId };
    if (accountId) {
      where.accountId = accountId;
    }

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

    return {
      total: contacts.length,
      optedIn: contacts.filter(c => c.optedIn && !c.optedOut).length,
      optedOut: contacts.filter(c => c.optedOut).length,
      active: contacts.filter(c => c.conversationStatus === 'active').length,
      waiting: contacts.filter(c => c.conversationStatus === 'waiting').length,
      resolved: contacts.filter(c => c.conversationStatus === 'resolved').length,
      blocked: contacts.filter(c => c.conversationStatus === 'blocked').length,
    };
  }
}
