import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BaseRepository } from '@edr/api-common';
import { Company } from './entities/company.entity';
import { ListCompaniesQueryDto } from './dto/list-companies-query.dto';
import { CompanyStatsResponseDto } from './dto/company-stats-response.dto';

@Injectable()
export class CompaniesRepository extends BaseRepository<Company> {
  constructor(
    @InjectRepository(Company)
    repo: Repository<Company>,
  ) {
    super(repo);
  }

  async findByTin(tin: string): Promise<Company | null> {
    return this.repository.findOne({ where: { tin } as any });
  }

  async findByType(type: string): Promise<Company[]> {
    return this.repository.find({ where: { type } as any, order: { name: 'ASC' } });
  }

  async findByName(name: string): Promise<Company[]> {
    return this.repository
      .createQueryBuilder('company')
      .where('company.name ILIKE :name', { name: `%${name}%` })
      .getMany();
  }

  async existsByTin(tin: string): Promise<boolean> {
    const count = await this.repository.count({ where: { tin } as any });
    return count > 0;
  }

  async findPaginated(
    query: ListCompaniesQueryDto,
  ): Promise<{ items: Company[]; total: number }> {
    const { page = 1, pageSize = 20, search, type, status } = query;

    const qb = this.repository
      .createQueryBuilder('company')
      .leftJoinAndSelect('company.companyProfiles', 'companyProfiles')
      .where('company.deleted_at IS NULL');

    if (type) {
      qb.andWhere('company.type = :type', { type });
    }

    if (status) {
      qb.andWhere('company.status = :status', { status });
    }

    if (search) {
      const term = `%${search.trim()}%`;
      qb.andWhere(
        `(company.name ILIKE :term
          OR company.tin ILIKE :term
          OR company.email ILIKE :term
          OR EXISTS (
            SELECT 1 FROM freight.company_profiles cp
            WHERE cp.company_id = company.id
              AND cp.reference ILIKE :term
              AND cp.deleted_at IS NULL
          ))`,
        { term },
      );
    }

    const [items, total] = await qb
      .orderBy('company.name', 'ASC')
      .skip((page - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

    return { items, total };
  }

  async getStats(): Promise<CompanyStatsResponseDto> {
    const rows: { status: string; count: string }[] = await this.repository
      .createQueryBuilder('company')
      .select('company.status', 'status')
      .addSelect('COUNT(*)', 'count')
      .where('company.deleted_at IS NULL')
      .groupBy('company.status')
      .getRawMany();

    const map = new Map(rows.map((r) => [r.status, parseInt(r.count, 10)]));
    const total = rows.reduce((sum, r) => sum + parseInt(r.count, 10), 0);

    return {
      total,
      active: map.get('active') ?? 0,
      pending: map.get('pending') ?? 0,
      suspended: map.get('suspended') ?? 0,
      blacklisted: map.get('blacklisted') ?? 0,
    };
  }
}
