import {
  Injectable,
  NotFoundException,
  ConflictException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Brand } from '../entities/brand.entity';
import { CreateBrandDto } from '../dto/create-brand.dto';
import { UpdateBrandDto } from '../dto/update-brand.dto';
import { TenantAwareService } from '../../../shared/services/tenant-aware.service';
import {
  PaginationDto,
  PaginatedResult,
  createPaginatedResult,
} from '../../../shared/dto/pagination.dto';
import { ClientService } from './client.service';

@Injectable()
export class BrandService extends TenantAwareService<Brand> {
  constructor(
    @InjectRepository(Brand)
    private readonly brandRepository: Repository<Brand>,
    private readonly clientService: ClientService,
  ) {
    super(brandRepository, 'Brand');
  }

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

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

    if (clientId) {
      queryBuilder.andWhere('brand.client_id = :clientId', { clientId });
    }

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

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

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

    return createPaginatedResult(data, total, pagination);
  }

  async findByClientId(tenantId: string, clientId: string): Promise<Brand[]> {
    return this.brandRepository.find({
      where: { tenant_id: tenantId, client_id: clientId },
      order: { name: 'ASC' },
    });
  }

  async create(tenantId: string, dto: CreateBrandDto): Promise<Brand> {
    // Verificar que el cliente existe y pertenece al tenant
    await this.clientService.findOneOrFail(tenantId, dto.client_id);

    const slug = dto.slug || this.generateSlug(dto.name);

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

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

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

    return this.brandRepository.save(brand);
  }

  async update(
    tenantId: string,
    id: string,
    dto: UpdateBrandDto,
  ): Promise<Brand> {
    const brand = await this.findOneOrFail(tenantId, id);

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

    Object.assign(brand, dto);
    return this.brandRepository.save(brand);
  }

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

  async findOneWithClient(tenantId: string, id: string): Promise<Brand> {
    const brand = await this.brandRepository.findOne({
      where: { id, tenant_id: tenantId },
      relations: ['client'],
    });

    if (!brand) {
      throw new NotFoundException('Brand not found');
    }

    return brand;
  }

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