import {
  Injectable,
  NotFoundException,
  ConflictException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, ILike } from 'typeorm';
import { Client } from '../entities/client.entity';
import { CreateClientDto } from '../dto/create-client.dto';
import { UpdateClientDto } from '../dto/update-client.dto';
import { TenantAwareService } from '../../../shared/services/tenant-aware.service';
import {
  PaginationDto,
  PaginatedResult,
  createPaginatedResult,
} from '../../../shared/dto/pagination.dto';

@Injectable()
export class ClientService extends TenantAwareService<Client> {
  constructor(
    @InjectRepository(Client)
    private readonly clientRepository: Repository<Client>,
  ) {
    super(clientRepository, 'Client');
  }

  async findAllPaginated(
    tenantId: string,
    pagination: PaginationDto,
  ): Promise<PaginatedResult<Client>> {
    const { skip, take, sortBy, sortOrder, search } = pagination;

    const queryBuilder = this.clientRepository
      .createQueryBuilder('client')
      .where('client.tenant_id = :tenantId', { tenantId })
      .andWhere('client.deleted_at IS NULL');

    if (search) {
      queryBuilder.andWhere(
        '(client.name ILIKE :search OR client.contact_email ILIKE :search)',
        { search: `%${search}%` },
      );
    }

    queryBuilder
      .orderBy(`client.${sortBy || 'created_at'}`, sortOrder || 'DESC')
      .skip(skip)
      .take(take);

    const [data, total] = await queryBuilder.getManyAndCount();

    return createPaginatedResult(data, total, pagination);
  }

  async create(tenantId: string, dto: CreateClientDto): Promise<Client> {
    const slug = dto.slug || this.generateSlug(dto.name);

    // Verificar slug unico en tenant
    const existing = await this.clientRepository.findOne({
      where: { tenant_id: tenantId, slug },
    });

    if (existing) {
      throw new ConflictException(`Client with slug '${slug}' already exists`);
    }

    const client = this.clientRepository.create({
      ...dto,
      tenant_id: tenantId,
      slug,
    });

    return this.clientRepository.save(client);
  }

  async update(
    tenantId: string,
    id: string,
    dto: UpdateClientDto,
  ): Promise<Client> {
    const client = await this.findOneOrFail(tenantId, id);

    // Si cambia slug, verificar unicidad
    if (dto.slug && dto.slug !== client.slug) {
      const existing = await this.clientRepository.findOne({
        where: { tenant_id: tenantId, slug: dto.slug },
      });
      if (existing) {
        throw new ConflictException(
          `Client with slug '${dto.slug}' already exists`,
        );
      }
    }

    Object.assign(client, dto);
    return this.clientRepository.save(client);
  }

  async remove(tenantId: string, id: string): Promise<void> {
    await this.findOneOrFail(tenantId, id);
    await this.clientRepository.softDelete({ id, tenant_id: tenantId });
  }

  async findBySlug(tenantId: string, slug: string): Promise<Client | null> {
    return this.clientRepository.findOne({
      where: { tenant_id: tenantId, slug },
    });
  }

  private generateSlug(name: string): string {
    return name
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-|-$/g, '');
  }
}
