import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ShortLink } from './entities/short-link.entity';

@Injectable()
export class ShortLinkService {
  private readonly logger = new Logger(ShortLinkService.name);
  private readonly CODE_LENGTH = 8;
  private readonly CODE_CHARS =
    'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

  constructor(
    @InjectRepository(ShortLink)
    private readonly shortLinkRepository: Repository<ShortLink>,
  ) {}

  /**
   * Génère un code court unique
   */
  private generateShortCode(): string {
    let code = '';
    for (let i = 0; i < this.CODE_LENGTH; i++) {
      code += this.CODE_CHARS.charAt(
        Math.floor(Math.random() * this.CODE_CHARS.length),
      );
    }
    return code;
  }

  /**
   * Crée un lien court pour une URL donnée
   * @param originalUrl L'URL originale à raccourcir
   * @returns Le code court généré
   */
  async createShortLink(originalUrl: string): Promise<string> {
    try {
      // Vérifier si un lien court existe déjà pour cette URL
      const existingLink = await this.shortLinkRepository.findOne({
        where: { original_url: originalUrl },
      });

      if (existingLink) {
        this.logger.log(
          `Short link already exists for URL: ${originalUrl.substring(0, 50)}...`,
        );
        return existingLink.code;
      }

      // Générer un code unique
      let code: string | undefined;
      let isUnique = false;
      let attempts = 0;
      const maxAttempts = 10;

      while (!isUnique && attempts < maxAttempts) {
        const generatedCode = this.generateShortCode();
        const existing = await this.shortLinkRepository.findOne({
          where: { code: generatedCode },
        });

        if (!existing) {
          code = generatedCode;
          isUnique = true;
        } else {
          attempts++;
        }
      }

      if (!isUnique || !code) {
        throw new Error(
          `Failed to generate unique short code after ${maxAttempts} attempts`,
        );
      }

      // Créer le lien court
      const shortLink = this.shortLinkRepository.create({
        code,
        original_url: originalUrl,
        click_count: 0,
      });

      await this.shortLinkRepository.save(shortLink);

      this.logger.log(
        `Created short link: ${code} for URL: ${originalUrl.substring(0, 50)}...`,
      );

      return code;
    } catch (error) {
      this.logger.error('Error creating short link:', error);
      throw error;
    }
  }

  /**
   * Récupère l'URL originale à partir d'un code court
   * @param code Le code court
   * @returns L'URL originale
   */
  async getOriginalUrl(code: string): Promise<string> {
    const shortLink = await this.shortLinkRepository.findOne({
      where: { code },
    });

    if (!shortLink) {
      throw new NotFoundException(`Short link with code ${code} not found`);
    }

    // Incrémenter le compteur de clics
    shortLink.click_count += 1;
    await this.shortLinkRepository.save(shortLink);

    return shortLink.original_url;
  }

  /**
   * Récupère les statistiques d'un lien court
   * @param code Le code court
   * @returns Les informations du lien court
   */
  async getShortLinkStats(code: string): Promise<ShortLink | null> {
    return await this.shortLinkRepository.findOne({
      where: { code },
    });
  }
}

