/**
 * Product Supplier Service
 * Servicio para gestion de proveedores de productos
 *
 * @module Products
 */

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

export interface CreateProductSupplierDto {
  productId: string;
  supplierId: string;
  supplierSku?: string;
  supplierName?: string;
  purchasePrice?: number;
  currency?: string;
  minOrderQty?: number;
  leadTimeDays?: number;
  isPreferred?: boolean;
}

export interface UpdateProductSupplierDto {
  supplierSku?: string;
  supplierName?: string;
  purchasePrice?: number;
  currency?: string;
  minOrderQty?: number;
  leadTimeDays?: number;
  isPreferred?: boolean;
  isActive?: boolean;
}

export interface ProductSupplierFilters {
  productId?: string;
  supplierId?: string;
  isPreferred?: boolean;
  isActive?: boolean;
}

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

export class ProductSupplierService {
  private repository: Repository<ProductSupplier>;

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

  async findAll(filters: ProductSupplierFilters): Promise<ProductSupplier[]> {
    const where: FindOptionsWhere<ProductSupplier> = {};

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

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

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

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

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

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

  async findByProduct(productId: string): Promise<ProductSupplier[]> {
    return this.repository.find({
      where: { productId, isActive: true },
      order: { isPreferred: 'DESC', purchasePrice: 'ASC' },
    });
  }

  async findBySupplier(supplierId: string): Promise<ProductSupplier[]> {
    return this.repository.find({
      where: { supplierId, isActive: true },
      relations: ['product'],
      order: { createdAt: 'DESC' },
    });
  }

  async findPreferred(productId: string): Promise<ProductSupplier | null> {
    return this.repository.findOne({
      where: { productId, isPreferred: true, isActive: true },
    });
  }

  async findCheapest(productId: string): Promise<ProductSupplier | null> {
    return this.repository.createQueryBuilder('ps')
      .where('ps.productId = :productId', { productId })
      .andWhere('ps.isActive = true')
      .andWhere('ps.purchasePrice IS NOT NULL')
      .orderBy('ps.purchasePrice', 'ASC')
      .getOne();
  }

  async findByProductAndSupplier(productId: string, supplierId: string): Promise<ProductSupplier | null> {
    return this.repository.findOne({
      where: { productId, supplierId },
    });
  }

  async create(data: CreateProductSupplierDto): Promise<ProductSupplier> {
    if (data.isPreferred) {
      await this.clearPreferred(data.productId);
    }

    const supplier = this.repository.create(data);
    return this.repository.save(supplier);
  }

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

    if (data.isPreferred && !supplier.isPreferred) {
      await this.clearPreferred(supplier.productId);
    }

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

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

  async setPreferred(id: string): Promise<ProductSupplier | null> {
    const supplier = await this.findById(id);
    if (!supplier) {
      return null;
    }

    await this.clearPreferred(supplier.productId);

    supplier.isPreferred = true;
    return this.repository.save(supplier);
  }

  async clearPreferred(productId: string): Promise<void> {
    await this.repository.update(
      { productId, isPreferred: true },
      { isPreferred: false }
    );
  }

  async updatePurchasePrice(
    id: string,
    purchasePrice: number,
    currency?: string
  ): Promise<ProductSupplier | null> {
    const supplier = await this.findById(id);
    if (!supplier) {
      return null;
    }

    supplier.purchasePrice = purchasePrice;
    if (currency) {
      supplier.currency = currency;
    }

    return this.repository.save(supplier);
  }

  async countByProduct(productId: string): Promise<number> {
    return this.repository.count({
      where: { productId, isActive: true },
    });
  }

  async countBySupplier(supplierId: string): Promise<number> {
    return this.repository.count({
      where: { supplierId, isActive: true },
    });
  }

  async getAveragePurchasePrice(productId: string): Promise<number | null> {
    const result = await this.repository.createQueryBuilder('ps')
      .select('AVG(ps.purchasePrice)', 'avgPrice')
      .where('ps.productId = :productId', { productId })
      .andWhere('ps.isActive = true')
      .andWhere('ps.purchasePrice IS NOT NULL')
      .getRawOne();

    return result?.avgPrice ? parseFloat(result.avgPrice) : null;
  }

  async getLowestPurchasePrice(productId: string): Promise<number | null> {
    const result = await this.repository.createQueryBuilder('ps')
      .select('MIN(ps.purchasePrice)', 'minPrice')
      .where('ps.productId = :productId', { productId })
      .andWhere('ps.isActive = true')
      .andWhere('ps.purchasePrice IS NOT NULL')
      .getRawOne();

    return result?.minPrice ? parseFloat(result.minPrice) : null;
  }
}
