import {
  Injectable,
  Inject,
  NotFoundException,
  BadRequestException,
  ForbiddenException,
} from '@nestjs/common';
import {
  IUserContactRepository,
  USER_CONTACT_REPOSITORY,
} from '../../domain/repositories/user-contact.repository.interface';
import {
  UserContactEntity,
  ContactType,
  NotificationType,
} from '../../domain/entities/user-contact.entity';

@Injectable()
export class UserContactService {
  constructor(
    @Inject(USER_CONTACT_REPOSITORY)
    private readonly contactRepo: IUserContactRepository,
  ) {}

  async addContact(
    userId: string,
    type: ContactType,
    value: string,
  ): Promise<UserContactEntity> {
    // Check if contact type already exists for user
    const existing = await this.contactRepo.findByUserIdAndType(userId, type);
    if (existing) {
      throw new BadRequestException(`Contact type ${type} already exists`);
    }

    const contact = UserContactEntity.create(userId, type, value);
    await this.contactRepo.save(contact);
    return contact;
  }

  async getContacts(userId: string): Promise<UserContactEntity[]> {
    return this.contactRepo.findByUserId(userId);
  }

  async getVerifiedContacts(userId: string): Promise<UserContactEntity[]> {
    return this.contactRepo.findVerifiedByUserId(userId);
  }

  async getContact(userId: string, type: ContactType): Promise<UserContactEntity> {
    const contact = await this.contactRepo.findByUserIdAndType(userId, type);
    if (!contact) {
      throw new NotFoundException(`Contact type ${type} not found`);
    }
    return contact;
  }

  async updateContactValue(
    userId: string,
    type: ContactType,
    value: string,
  ): Promise<UserContactEntity> {
    const contact = await this.getContact(userId, type);
    contact.updateValue(value);
    await this.contactRepo.update(contact);
    return contact;
  }

  async deleteContact(userId: string, type: ContactType): Promise<void> {
    const contact = await this.getContact(userId, type);
    await this.contactRepo.delete(contact.id);
  }

  async requestVerification(
    userId: string,
    type: ContactType,
  ): Promise<{ code: string; expiresAt: Date }> {
    const contact = await this.getContact(userId, type);

    if (contact.isVerified) {
      throw new BadRequestException('Contact is already verified');
    }

    const code = contact.generateVerificationCode();
    await this.contactRepo.update(contact);

    // In production, send the code via email/SMS/etc.
    // For now, return it directly (development mode)
    return {
      code,
      expiresAt: contact.verificationExpiresAt!,
    };
  }

  async verifyContact(
    userId: string,
    type: ContactType,
    code: string,
  ): Promise<UserContactEntity> {
    const contact = await this.getContact(userId, type);

    if (contact.isVerified) {
      throw new BadRequestException('Contact is already verified');
    }

    const success = contact.verify(code);
    if (!success) {
      throw new BadRequestException('Invalid or expired verification code');
    }

    await this.contactRepo.update(contact);
    return contact;
  }

  async markAsVerified(
    userId: string,
    type: ContactType,
    displayName?: string,
  ): Promise<UserContactEntity> {
    const contact = await this.getContact(userId, type);
    contact.markAsVerified(displayName);
    await this.contactRepo.update(contact);
    return contact;
  }

  async enableNotifications(
    userId: string,
    type: ContactType,
    notificationTypes: NotificationType[],
  ): Promise<UserContactEntity> {
    const contact = await this.getContact(userId, type);

    if (!contact.isVerified) {
      throw new ForbiddenException('Contact must be verified before enabling notifications');
    }

    contact.enableNotifications(notificationTypes);
    await this.contactRepo.update(contact);
    return contact;
  }

  async disableNotifications(
    userId: string,
    type: ContactType,
  ): Promise<UserContactEntity> {
    const contact = await this.getContact(userId, type);
    contact.disableNotifications();
    await this.contactRepo.update(contact);
    return contact;
  }

  async updateNotificationTypes(
    userId: string,
    type: ContactType,
    notificationTypes: NotificationType[],
  ): Promise<UserContactEntity> {
    const contact = await this.getContact(userId, type);

    if (!contact.notificationEnabled) {
      throw new BadRequestException('Notifications are not enabled for this contact');
    }

    contact.updateNotificationTypes(notificationTypes);
    await this.contactRepo.update(contact);
    return contact;
  }

  // Admin methods
  async findByNotificationType(
    notificationType: NotificationType,
    options?: { limit?: number; offset?: number },
  ): Promise<UserContactEntity[]> {
    return this.contactRepo.findByNotificationType(notificationType, options);
  }

  async getVerifiedContactStats(): Promise<Record<ContactType, number>> {
    return this.contactRepo.countVerifiedByType();
  }
}
