import {
  Injectable,
  NotFoundException,
  ConflictException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Product } from '../entities/product.entity';
import { CreateProductDto } from '../dto/create-product.dto';
import { UpdateProductDto } from '../dto/update-product.dto';
import { TenantAwareService } from '../../../shared/services/tenant-aware.service';
import {
  PaginationDto,
  PaginatedResult,
  createPaginatedResult,
} from '../../../shared/dto/pagination.dto';
import { BrandService } from './brand.service';

@Injectable()
export class ProductService extends TenantAwareService<Product> {
  constructor(
    @InjectRepository(Product)
    private readonly productRepository: Repository<Product>,
    private readonly brandService: BrandService,
  ) {
    super(productRepository, 'Product');
  }

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

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

    if (brandId) {
      queryBuilder.andWhere('product.brand_id = :brandId', { brandId });
    }

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

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

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

    return createPaginatedResult(data, total, pagination);
  }

  async findByBrandId(tenantId: string, brandId: string): Promise<Product[]> {
    return this.productRepository.find({
      where: { tenant_id: tenantId, brand_id: brandId },
      order: { name: 'ASC' },
    });
  }

  async create(tenantId: string, dto: CreateProductDto): Promise<Product> {
    // Verificar que la marca existe y pertenece al tenant
    await this.brandService.findOneOrFail(tenantId, dto.brand_id);

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

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

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

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

    return this.productRepository.save(product);
  }

  async update(
    tenantId: string,
    id: string,
    dto: UpdateProductDto,
  ): Promise<Product> {
    const product = await this.findOneOrFail(tenantId, id);

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

    Object.assign(product, dto);
    return this.productRepository.save(product);
  }

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

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

    if (!product) {
      throw new NotFoundException('Product not found');
    }

    return product;
  }

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