/**
 * Product Price Service
 * Servicio para gestion de precios de productos (listas de precios, promociones)
 *
 * @module Products
 */

import { Repository, FindOptionsWhere } from 'typeorm';
import { AppDataSource } from '../../../shared/database/typeorm.config';
import { ProductPrice } from '../entities/product-price.entity';

export interface CreateProductPriceDto {
  productId: string;
  priceType?: 'standard' | 'wholesale' | 'retail' | 'promo';
  priceListName?: string;
  price: number;
  currency?: string;
  minQuantity?: number;
  validFrom?: Date;
  validTo?: Date;
}

export interface UpdateProductPriceDto {
  priceType?: 'standard' | 'wholesale' | 'retail' | 'promo';
  priceListName?: string;
  price?: number;
  currency?: string;
  minQuantity?: number;
  validFrom?: Date;
  validTo?: Date;
  isActive?: boolean;
}

export interface ProductPriceFilters {
  productId: string;
  priceType?: 'standard' | 'wholesale' | 'retail' | 'promo';
  isActive?: boolean;
  validAt?: Date;
}

export interface ServiceContext {
  tenantId: string;
  userId?: string;
}

export class ProductPriceService {
  private repository: Repository<ProductPrice>;

  constructor() {
    this.repository = AppDataSource.getRepository(ProductPrice);
  }

  async findAll(filters: ProductPriceFilters): Promise<ProductPrice[]> {
    const where: FindOptionsWhere<ProductPrice> = {
      productId: filters.productId,
    };

    if (filters.priceType) {
      where.priceType = filters.priceType;
    }

    if (filters.isActive !== undefined) {
      where.isActive = filters.isActive;
    }

    return this.repository.find({
      where,
      relations: ['product'],
      order: { priceType: 'ASC', minQuantity: 'ASC' },
    });
  }

  async findById(id: string): Promise<ProductPrice | null> {
    return this.repository.findOne({
      where: { id },
      relations: ['product'],
    });
  }

  async findActivePrice(
    productId: string,
    priceType: 'standard' | 'wholesale' | 'retail' | 'promo' = 'standard',
    quantity: number = 1,
    date: Date = new Date()
  ): Promise<ProductPrice | null> {
    return this.repository.createQueryBuilder('price')
      .where('price.productId = :productId', { productId })
      .andWhere('price.priceType = :priceType', { priceType })
      .andWhere('price.isActive = true')
      .andWhere('price.minQuantity <= :quantity', { quantity })
      .andWhere('price.validFrom <= :date', { date })
      .andWhere('(price.validTo IS NULL OR price.validTo >= :date)', { date })
      .orderBy('price.minQuantity', 'DESC')
      .getOne();
  }

  async findBestPrice(
    productId: string,
    quantity: number = 1,
    date: Date = new Date()
  ): Promise<ProductPrice | null> {
    return this.repository.createQueryBuilder('price')
      .where('price.productId = :productId', { productId })
      .andWhere('price.isActive = true')
      .andWhere('price.minQuantity <= :quantity', { quantity })
      .andWhere('price.validFrom <= :date', { date })
      .andWhere('(price.validTo IS NULL OR price.validTo >= :date)', { date })
      .orderBy('price.price', 'ASC')
      .getOne();
  }

  async findByProduct(productId: string): Promise<ProductPrice[]> {
    return this.repository.find({
      where: { productId },
      order: { priceType: 'ASC', minQuantity: 'ASC' },
    });
  }

  async findActivePricesByProduct(productId: string, date: Date = new Date()): Promise<ProductPrice[]> {
    return this.repository.createQueryBuilder('price')
      .where('price.productId = :productId', { productId })
      .andWhere('price.isActive = true')
      .andWhere('price.validFrom <= :date', { date })
      .andWhere('(price.validTo IS NULL OR price.validTo >= :date)', { date })
      .orderBy('price.priceType', 'ASC')
      .addOrderBy('price.minQuantity', 'ASC')
      .getMany();
  }

  async create(data: CreateProductPriceDto): Promise<ProductPrice> {
    const price = this.repository.create({
      ...data,
      validFrom: data.validFrom || new Date(),
    });
    return this.repository.save(price);
  }

  async update(
    id: string,
    data: UpdateProductPriceDto
  ): Promise<ProductPrice | null> {
    const price = await this.findById(id);
    if (!price) {
      return null;
    }

    Object.assign(price, data);
    return this.repository.save(price);
  }

  async delete(id: string): Promise<boolean> {
    const result = await this.repository.delete({ id });
    return result.affected ? result.affected > 0 : false;
  }

  async deactivate(id: string): Promise<ProductPrice | null> {
    const price = await this.findById(id);
    if (!price) {
      return null;
    }

    price.isActive = false;
    return this.repository.save(price);
  }

  async deactivateByProduct(productId: string, priceType?: 'standard' | 'wholesale' | 'retail' | 'promo'): Promise<number> {
    const where: FindOptionsWhere<ProductPrice> = { productId };
    if (priceType) {
      where.priceType = priceType;
    }

    const result = await this.repository.update(where, { isActive: false });
    return result.affected || 0;
  }

  async setStandardPrice(productId: string, price: number, currency: string = 'MXN'): Promise<ProductPrice> {
    const existing = await this.repository.findOne({
      where: { productId, priceType: 'standard', minQuantity: 1 },
    });

    if (existing) {
      existing.price = price;
      existing.currency = currency;
      existing.isActive = true;
      return this.repository.save(existing);
    }

    return this.create({
      productId,
      priceType: 'standard',
      price,
      currency,
      minQuantity: 1,
    });
  }

  async createPromoPrice(
    productId: string,
    price: number,
    validFrom: Date,
    validTo: Date,
    priceListName?: string
  ): Promise<ProductPrice> {
    return this.create({
      productId,
      priceType: 'promo',
      price,
      priceListName,
      validFrom,
      validTo,
    });
  }

  async getExpiredPromotions(date: Date = new Date()): Promise<ProductPrice[]> {
    return this.repository.createQueryBuilder('price')
      .where('price.priceType = :priceType', { priceType: 'promo' })
      .andWhere('price.isActive = true')
      .andWhere('price.validTo < :date', { date })
      .leftJoinAndSelect('price.product', 'product')
      .getMany();
  }

  async deactivateExpiredPromotions(date: Date = new Date()): Promise<number> {
    const result = await this.repository.createQueryBuilder()
      .update(ProductPrice)
      .set({ isActive: false })
      .where('priceType = :priceType', { priceType: 'promo' })
      .andWhere('isActive = true')
      .andWhere('validTo < :date', { date })
      .execute();

    return result.affected || 0;
  }
}
