/**
 * Customers Service
 * Mecánicas Diesel - ERP Suite
 *
 * Business logic for customer management.
 */

import { DataSource, Repository, ILike, FindOptionsWhere } from 'typeorm';
import { Customer, CustomerType } from '../entities/customer.entity';
import { CreateCustomerDto, UpdateCustomerDto, CustomerFilters } from '../customers.dto';

export class CustomersService {
  private repository: Repository<Customer>;

  constructor(private dataSource: DataSource) {
    this.repository = dataSource.getRepository(Customer);
  }

  /**
   * Create a new customer
   */
  async create(tenantId: string, dto: CreateCustomerDto, userId?: string): Promise<Customer> {
    const customer = this.repository.create({
      tenantId,
      ...dto,
      createdBy: userId,
    });

    return this.repository.save(customer);
  }

  /**
   * Find customer by ID
   */
  async findById(tenantId: string, id: string): Promise<Customer | null> {
    return this.repository.findOne({
      where: { id, tenantId },
    });
  }

  /**
   * Find customer by email
   */
  async findByEmail(tenantId: string, email: string): Promise<Customer | null> {
    return this.repository.findOne({
      where: { email, tenantId },
    });
  }

  /**
   * Find customer by phone
   */
  async findByPhone(tenantId: string, phone: string): Promise<Customer | null> {
    return this.repository.findOne({
      where: [
        { phone, tenantId },
        { phoneSecondary: phone, tenantId },
      ],
    });
  }

  /**
   * Find customer by RFC
   */
  async findByRfc(tenantId: string, rfc: string): Promise<Customer | null> {
    return this.repository.findOne({
      where: { rfc, tenantId },
    });
  }

  /**
   * Find all customers with filters and pagination
   */
  async findAll(
    tenantId: string,
    filters: CustomerFilters
  ): Promise<{ data: Customer[]; total: number; page: number; limit: number }> {
    const { page, limit, search, customerType, isActive, hasCredit } = filters;
    const skip = (page - 1) * limit;

    const where: FindOptionsWhere<Customer> = { tenantId };

    if (customerType) {
      where.customerType = customerType;
    }

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

    const queryBuilder = this.repository.createQueryBuilder('customer')
      .where('customer.tenant_id = :tenantId', { tenantId });

    if (customerType) {
      queryBuilder.andWhere('customer.customer_type = :customerType', { customerType });
    }

    if (isActive !== undefined) {
      queryBuilder.andWhere('customer.is_active = :isActive', { isActive });
    }

    if (hasCredit) {
      queryBuilder.andWhere('customer.credit_limit > 0');
    }

    if (search) {
      queryBuilder.andWhere(
        '(customer.name ILIKE :search OR customer.email ILIKE :search OR customer.phone ILIKE :search OR customer.rfc ILIKE :search)',
        { search: `%${search}%` }
      );
    }

    const [data, total] = await queryBuilder
      .orderBy('customer.name', 'ASC')
      .skip(skip)
      .take(limit)
      .getManyAndCount();

    return { data, total, page, limit };
  }

  /**
   * Search customers by name, email, phone or RFC
   */
  async search(tenantId: string, query: string, limit: number = 10): Promise<Customer[]> {
    return this.repository.createQueryBuilder('customer')
      .where('customer.tenant_id = :tenantId', { tenantId })
      .andWhere('customer.is_active = true')
      .andWhere(
        '(customer.name ILIKE :query OR customer.email ILIKE :query OR customer.phone ILIKE :query OR customer.rfc ILIKE :query)',
        { query: `%${query}%` }
      )
      .orderBy('customer.name', 'ASC')
      .take(limit)
      .getMany();
  }

  /**
   * Update a customer
   */
  async update(tenantId: string, id: string, dto: UpdateCustomerDto): Promise<Customer | null> {
    const customer = await this.findById(tenantId, id);
    if (!customer) {
      return null;
    }

    Object.assign(customer, dto);
    return this.repository.save(customer);
  }

  /**
   * Soft delete - deactivate customer
   */
  async deactivate(tenantId: string, id: string): Promise<boolean> {
    const result = await this.repository.update(
      { id, tenantId },
      { isActive: false }
    );
    return (result.affected ?? 0) > 0;
  }

  /**
   * Reactivate customer
   */
  async activate(tenantId: string, id: string): Promise<boolean> {
    const result = await this.repository.update(
      { id, tenantId },
      { isActive: true }
    );
    return (result.affected ?? 0) > 0;
  }

  /**
   * Update customer stats after service completion
   */
  async updateStats(
    tenantId: string,
    customerId: string,
    orderTotal: number
  ): Promise<void> {
    await this.repository.createQueryBuilder()
      .update(Customer)
      .set({
        totalOrders: () => 'total_orders + 1',
        totalSpent: () => `total_spent + ${orderTotal}`,
        lastVisitAt: new Date(),
      })
      .where('id = :customerId AND tenant_id = :tenantId', { customerId, tenantId })
      .execute();
  }

  /**
   * Get customer statistics
   */
  async getStats(tenantId: string): Promise<{
    total: number;
    active: number;
    byType: Record<string, number>;
    withCredit: number;
  }> {
    const [total, active, withCredit] = await Promise.all([
      this.repository.count({ where: { tenantId } }),
      this.repository.count({ where: { tenantId, isActive: true } }),
      this.repository.createQueryBuilder('c')
        .where('c.tenant_id = :tenantId', { tenantId })
        .andWhere('c.credit_limit > 0')
        .getCount(),
    ]);

    const byTypeRaw = await this.repository.createQueryBuilder('c')
      .select('c.customer_type', 'type')
      .addSelect('COUNT(*)', 'count')
      .where('c.tenant_id = :tenantId', { tenantId })
      .groupBy('c.customer_type')
      .getRawMany();

    const byType: Record<string, number> = {};
    byTypeRaw.forEach((row) => {
      byType[row.type] = parseInt(row.count, 10);
    });

    return { total, active, byType, withCredit };
  }
}
