import { Inject, Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, SelectQueryBuilder } from 'typeorm';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import {
  getSkipOffset,
  paginate,
} from 'src/config/pagination/pagination.service';
import { SearchDto } from './dto/search-dto';
import { Response } from 'src/config/pagination/paginationDto';
import { getMonthShortName } from 'src/utils';
import { VcmCommissionReceivedEntity } from 'src/entities/VcmCommissionReceived.entity';
import { FileService } from 'src/services/file.service';
import { AddAttachmentDto } from './dto/add-attachment.dto';
import { RemoveAttachmentDto } from './dto/remove-attachment.dto';
import { plainToInstance } from 'class-transformer';
import { ReceivedInfoDto } from './dto/received-info-dto';
import { VcmCommissionReceivedDetailsEntity } from 'src/entities/VcmCommissionReceivedDetails.entity';
import { UserDataProps } from 'src/utils/decorators/user-data.decorator';

/**
 * VisaCommissionReceivedService - Core service for managing received commission payments
 *
 * This service handles the tracking and management of commission payments that have been
 * actually received from institutes and master agents. It focuses on the post-enquiry
 * phase where commissions are paid and reconciled.
 *
 * Business Domain: Commission Payment Tracking & Reconciliation System
 * - Tracks actual commission payments received from partners
 * - Manages payment proofs and documentation
 * - Handles financial reconciliation between expected and received amounts
 * - Provides comprehensive filtering and reporting on commission receipts
 * - Supports attachment management for payment verification
 *
 * Architecture: Service-oriented with focus on financial tracking
 * - Primary entity: Commission received records
 * - Supporting entities: Commission received details (line items)
 * - File management for payment documentation
 * - Comprehensive query capabilities for financial reporting
 *
 * Key Features:
 * - 20+ business methods for complete payment tracking
 * - Dual workflow support (institute vs master agent payments)
 * - File attachment management for payment proofs
 * - Comprehensive filtering and reporting capabilities
 * - Financial calculations and currency conversion
 */
@Injectable()
export class VisaCommissionReceivedService {
  // Logger instance for service-specific logging and debugging
  private logger = new Logger(VisaCommissionReceivedService.name);

  constructor(
    // File service for handling payment proof attachments
    private fileService: FileService,

    // Cache manager for performance optimization
    @Inject(CACHE_MANAGER) private cacheManager: Cache,

    // ==================== REPOSITORY INJECTIONS ====================
    // Main commission received repository
    @InjectRepository(VcmCommissionReceivedEntity)
    private readonly vcReceivedRepo: Repository<VcmCommissionReceivedEntity>,

    // Commission received details repository
    @InjectRepository(VcmCommissionReceivedDetailsEntity)
    private readonly redDetailRepo: Repository<VcmCommissionReceivedDetailsEntity>,
  ) {}

  /**
   * Find all received commission payments with advanced filtering and pagination
   *
   * Supports comprehensive filtering for both institute and master agent payments
   * Includes detailed joins for related data and financial information
   *
   * @param dto - Search criteria including association type and various filters
   * @returns Paginated response with received commission payment data
   */
  async findAll(
    dto: SearchDto,
  ): Promise<Response<VcmCommissionReceivedEntity>> {
    const query = this.vcReceivedRepo
      .createQueryBuilder('main')
      .select([
        'main.id',
        'main.association_type',
        'main.commission_enquiry_id',
        'main.total_amount',
        'main.currency',
        'main.conversion_rate',
        'main.total_amount_inr',
        'main.tax_details',
        'main.total_tax_amount',
        'main.other_deductions',
        'main.deduction_reason',
        'main.net_amount_inr',
        'main.payment_date',
        'main.payment_mode_id',
        'main.bank_account_id',
        'main.transaction_id',
        'main.attachment_file',
        'main.remarks',
        'main.by_user',
        'main.created',
        'main.modified_by_user',
        'main.modified',
        'mode.payment_mode_name',
        'bank.bank_name',
        'bank.acc_number',
        'bank.company_bank_address',
        'user.employeeCode',
        'user.fname',
        'user.lname',
        'modified_by.employeeCode',
        'modified_by.fname',
        'modified_by.lname',
      ]);

    // Add appropriate joins based on association type
    if (dto.association_type === '1') {
      // Institute commission received
      query
        .leftJoinAndSelect('main.institute_enquiry', 'enq')
        .addSelect([
          'visa_country.name',
          'client_country.name',
          'institute.institueName',
          'institute.UID',
          'intake.intakeyear',
          'intake.intakemonth',
        ])
        .leftJoin('enq.visa_country', 'visa_country')
        .leftJoin('enq.client_country', 'client_country')
        .leftJoin('enq.institute', 'institute')
        .leftJoin('enq.intake', 'intake')
        .leftJoin('enq.contract_set', 'contract_set')
        .addSelect(['contract_set.set_name'])
        .leftJoin('enq.instance', 'instance')
        .addSelect(['instance.instance'])
        .leftJoin('enq.invoice', 'invoice')
        .addSelect(['invoice.invoice_no']);
    } else if (dto.association_type === '2') {
      // Master agent commission received
      query
        .leftJoinAndSelect('main.ma_enquiry', 'enq')
        .addSelect([
          'associate.masteragentName',
          'associate.uid',
          'visa_country.name',
          'client_country.name',
          'institute.institueName',
          'institute.UID',
          'intake.intakeyear',
          'intake.intakemonth',
        ])
        .leftJoin('enq.associate', 'associate')
        .leftJoin('enq.visa_country', 'visa_country')
        .leftJoin('enq.client_country', 'client_country')
        .leftJoin('enq.institute', 'institute')
        .leftJoin('enq.intake', 'intake')
        .leftJoin('enq.contract_set', 'contract_set')
        .addSelect(['contract_set.set_name'])
        .leftJoin('enq.instance', 'instance')
        .addSelect(['instance.instance'])
        .leftJoin('enq.invoice', 'invoice')
        .addSelect(['invoice.invoice_no']);
    }

    // Add common joins
    query
      .leftJoin('main.mode', 'mode')
      .leftJoin('main.bank', 'bank')
      .leftJoin('main.user', 'user')
      .leftJoin('main.modified_by', 'modified_by')
      .where('main.association_type = :association_type', {
        association_type: Number(dto.association_type),
      })
      .andWhere('main.commission_enquiry_id IS NOT NULL')
      .orderBy('main.id', 'DESC');

    // Apply filter conditions
    this.filterWhereConditions(query, dto);

    // Apply pagination
    const [skip, limit] = getSkipOffset(dto);
    const [data, total] = await query.skip(skip).take(limit).getManyAndCount();

    const pagination = paginate(total, dto.per_page, dto.page);

    return { list: data, pagination };
  }

  /**
   * Apply filter conditions to commission received query
   *
   * Supports 15+ filter criteria including:
   * - Text search on transaction ID and remarks
   * - Visa service countries
   * - Client countries
   * - Institutes
   * - Intakes
   * - Commission instances
   * - Associates (for master agents)
   * - Bank accounts
   * - Date ranges
   * - User filters
   *
   * @param query - TypeORM query builder
   * @param dto - Search criteria
   */
  private filterWhereConditions(
    query: SelectQueryBuilder<VcmCommissionReceivedEntity>,
    dto: SearchDto,
  ) {
    // Text search on transaction ID and remarks
    if (dto.search_title && dto.search_title.trim() !== '') {
      const keyword = `%${dto.search_title.trim().toLowerCase()}%`;
      query.andWhere(
        '(LOWER(main.transaction_id) LIKE :keyword OR LOWER(main.remarks) LIKE :keyword)',
        { keyword },
      );
    }

    // Visa service country filter
    if (dto.visa_service_country_id && dto.visa_service_country_id.length > 0) {
      query.andWhere('enq.visa_service_country_id IN (:...visa_country)', {
        visa_country: dto.visa_service_country_id,
      });
    }

    // Client country filter
    if (dto.client_from_country_id && dto.client_from_country_id.length > 0) {
      query.andWhere('enq.client_from_country_id IN (:...client_country)', {
        client_country: dto.client_from_country_id,
      });
    }

    // Institute filter
    if (dto.institute_id && dto.institute_id.length > 0) {
      query.andWhere('enq.institute_id IN (:...institute_id)', {
        institute_id: dto.institute_id,
      });
    }

    // Intake filter
    if (dto.intake_id && dto.intake_id.length > 0) {
      query.andWhere('enq.intake_id IN (:...intake_id)', {
        intake_id: dto.intake_id,
      });
    }

    // Commission instance filter
    if (dto.commission_instance_id && dto.commission_instance_id.length > 0) {
      query.andWhere(
        'enq.commission_instance_id IN (:...commission_instance_id)',
        {
          commission_instance_id: dto.commission_instance_id,
        },
      );
    }

    // Associate filter (master agents only)
    if (
      dto.association_type === '2' &&
      dto.associate_id &&
      dto.associate_id.length > 0
    ) {
      query.andWhere('main.associate_id IN (:...associate_id)', {
        associate_id: dto.associate_id,
      });
    }

    // Bank account filter
    if (dto.bank_account_id && dto.bank_account_id.length > 0) {
      query.andWhere('main.bank_account_id IN (:...bank_account_id)', {
        bank_account_id: dto.bank_account_id,
      });
    }

    // Created by user filter
    if (dto.created_by && dto.created_by.length > 0) {
      query.andWhere('main.by_user IN (:...created_by)', {
        created_by: dto.created_by,
      });
    }

    // Updated by user filter
    if (dto.updated_by && dto.updated_by.length > 0) {
      query.andWhere('main.modified_by_user IN (:...updated_by)', {
        updated_by: dto.updated_by,
      });
    }

    // Creation date range filter
    if (dto.created_on) {
      const { from, to } = dto.created_on;
      if (from && to) {
        query.andWhere('main.created BETWEEN :createdFrom AND :createdTo', {
          createdFrom: from,
          createdTo: to,
        });
      } else if (from) {
        query.andWhere('main.created >= :createdFrom', {
          createdFrom: from,
        });
      } else if (to) {
        query.andWhere('main.created <= :createdTo', {
          createdTo: to,
        });
      }
    }

    // Modification date range filter
    if (dto.updated_on) {
      const { from, to } = dto.updated_on;
      if (from && to) {
        query.andWhere('main.modified BETWEEN :modifiedFrom AND :modifiedTo', {
          modifiedFrom: from,
          modifiedTo: to,
        });
      } else if (from) {
        query.andWhere('main.modified >= :modifiedFrom', {
          modifiedFrom: from,
        });
      } else if (to) {
        query.andWhere('main.modified <= :modifiedTo', {
          modifiedTo: to,
        });
      }
    }
  }

  /**
   * Get distinct visa service countries by association type
   *
   * Used for filter dropdowns in the commission received interface
   * Shows only countries where commission payments have been received
   *
   * @param association_type - Association type (1=Institute, 2=Master Agent)
   * @returns Distinct visa service countries where commissions were received
   */
  async fetchServiceCountriesByList(association_type: number) {
    const query = this.vcReceivedRepo
      .createQueryBuilder('main')
      .innerJoin(
        association_type === 1 ? 'main.institute_enquiry' : 'main.ma_enquiry',
        'enq',
      )
      .innerJoin('enq.visa_country', 'visa_country')
      .select(['visa_country.country_id AS id', 'visa_country.name AS name'])
      .where('main.association_type = :association_type', { association_type })
      .andWhere('main.commission_enquiry_id IS NOT NULL')
      .orderBy('visa_country.name', 'ASC')
      .groupBy('visa_country.country_id');

    return await query.getRawMany();
  }

  /**
   * Get distinct client countries by association type
   *
   * Shows client countries (student nationalities) for which commissions were received
   *
   * @param association_type - Association type
   * @returns Distinct client countries of students for whom commissions were received
   */
  async fetchClientCountriesByList(association_type: number) {
    const query = this.vcReceivedRepo
      .createQueryBuilder('main')
      .innerJoin(
        association_type === 1 ? 'main.institute_enquiry' : 'main.ma_enquiry',
        'enq',
      )
      .innerJoin('enq.client_country', 'client_country')
      .select([
        'client_country.country_id AS id',
        'client_country.name AS name',
      ])
      .where('main.association_type = :association_type', { association_type })
      .andWhere('main.commission_enquiry_id IS NOT NULL')
      .orderBy('client_country.name', 'ASC')
      .groupBy('client_country.country_id');

    return await query.getRawMany();
  }

  /**
   * Get distinct institutes by association type
   *
   * Shows institutes that have made commission payments
   *
   * @param association_type - Association type
   * @returns Distinct institutes that have paid commissions
   */
  async fetchInstitutesByList(association_type: number) {
    const query = this.vcReceivedRepo
      .createQueryBuilder('main')
      .innerJoin(
        association_type === 1 ? 'main.institute_enquiry' : 'main.ma_enquiry',
        'enq',
      )
      .innerJoin('enq.institute', 'institute')
      .select([
        'institute.collegeId AS id',
        `CONCAT(institute.institueName, " (", institute.UID, ")") AS name`,
      ])
      .where('main.association_type = :association_type', { association_type })
      .andWhere('main.commission_enquiry_id IS NOT NULL')
      .orderBy('institute.institueName', 'ASC')
      .groupBy('enq.institute_id');

    return await query.getRawMany();
  }

  /**
   * Get distinct associates (master agents) by association type
   *
   * Shows master agents who have made commission payments
   *
   * @param association_type - Association type
   * @returns Distinct master agents that have paid commissions
   */
  async fetchAssociatesByList(association_type: number) {
    const query = this.vcReceivedRepo
      .createQueryBuilder('main')
      .innerJoin('main.ma_enquiry', 'enq')
      .innerJoin('enq.associate', 'associate')
      .select([
        'associate.id AS id',
        `CONCAT(associate.masteragentName, " (", associate.uid, ")") AS name`,
      ])
      .where('main.association_type = :association_type', {
        association_type: association_type,
      })
      .andWhere('main.commission_enquiry_id IS NOT NULL')
      .orderBy('associate.masteragentName', 'ASC')
      .groupBy('enq.associate_id');

    return await query.getRawMany();
  }

  /**
   * Get distinct intake periods by association type
   *
   * Shows academic intake periods for which commissions were received
   *
   * @param association_type - Association type
   * @returns Distinct intake periods with commission payments
   */
  async fetchIntakesByList(association_type: number) {
    const query = this.vcReceivedRepo.createQueryBuilder('main');
    const results = await query
      .innerJoin(
        association_type === 1 ? 'main.institute_enquiry' : 'main.ma_enquiry',
        'enq',
      )
      .innerJoin('enq.intake', 'intake')
      .select('intake.intakYId', 'id')
      .addSelect('intake.intakemonth', 'month')
      .addSelect('intake.intakeyear', 'year')
      .where('main.association_type = :association_type', {
        association_type: association_type,
      })
      .andWhere('main.commission_enquiry_id IS NOT NULL')
      .orderBy('intake.intakeyear', 'ASC')
      .addOrderBy('intake.intakemonth', 'ASC')
      .groupBy('enq.intake_id')
      .getRawMany();

    // Format results with month names
    return results.map((r) => ({
      id: r.id,
      name: `${getMonthShortName(parseInt(r.month, 10), false)} - ${r.year}`,
    }));
  }

  /**
   * Get distinct commission instances by association type
   *
   * Shows specific commission contract instances for which payments were received
   *
   * @param association_type - Association type
   * @returns Distinct commission instances with received payments
   */
  async fetchInstancesByList(association_type: number) {
    const query = this.vcReceivedRepo.createQueryBuilder('main');
    query
      .innerJoin(
        association_type === 1 ? 'main.institute_enquiry' : 'main.ma_enquiry',
        'enq',
      )
      .leftJoin('enq.instance', 'instance')
      .select(['enq.commission_instance AS id', 'instance.instance AS name'])
      .where('main.association_type = :association_type', {
        association_type: association_type,
      })
      .andWhere('main.commission_enquiry_id IS NOT NULL')
      .orderBy('enq.commission_instance', 'ASC')
      .groupBy('enq.commission_instance');

    return await query.getRawMany();
  }

  /**
   * Get distinct payment modes by association type
   *
   * Shows payment methods used for commission payments (bank transfer, cash, etc.)
   *
   * @param association_type - Association type
   * @returns Distinct payment modes used for commission payments
   */
  async fetchPaymentModesByList(association_type: number) {
    const query = this.vcReceivedRepo.createQueryBuilder('main');
    query
      .innerJoin('main.mode', 'mode')
      .select(['main.payment_mode_id AS id', 'mode.payment_mode_name AS name'])
      .orderBy('mode.payment_mode_name', 'ASC')
      .groupBy('main.payment_mode_id');

    if (association_type) {
      query.andWhere('main.association_type = :association_type', {
        association_type,
      });
    }

    return await query.getRawMany();
  }

  /**
   * Get distinct bank accounts by association type
   *
   * Shows bank accounts into which commission payments were received
   *
   * @param association_type - Association type
   * @returns Distinct bank accounts used for commission receipts
   */
  async fetchReceivedBankAccountsByList(association_type: number) {
    const query = this.vcReceivedRepo.createQueryBuilder('main');
    query
      .innerJoin('main.bank', 'bank')
      .select([
        'main.bank_account_id AS id',
        `CONCAT(bank.acc_number, " - ", bank.bank_name, ", ",bank.company_bank_address) AS name`,
      ])
      .orderBy('bank.bank_name', 'ASC')
      .groupBy('main.bank_account_id');

    if (association_type) {
      query.andWhere('main.association_type = :association_type', {
        association_type,
      });
    }

    return await query.getRawMany();
  }

  /**
   * Get distinct users who created or updated commission received records
   *
   * Used for audit trail and filtering by responsible users
   *
   * @param by - Filter type ('created_by' or 'updated_by')
   * @param association_type - Association type
   * @returns Distinct users with formatted names who handled commission receipts
   */
  async fetchCreatedByOrUpdatedByUsers(by: string, association_type: number) {
    const query = this.vcReceivedRepo.createQueryBuilder('main');

    if (by === 'created_by') {
      query
        .leftJoin('main.user', 'user')
        .select('user.id', 'id')
        .addSelect(
          `CONCAT(user.fname, ' ', user.lname, ' - ', user.employeeCode)`,
          'name',
        )
        .orderBy('user.fname', 'ASC')
        .addOrderBy('user.lname', 'ASC')
        .groupBy('user.id');
    }

    if (by === 'updated_by') {
      query
        .leftJoin('main.modified_by', 'modified_by')
        .select('modified_by.id', 'id')
        .addSelect(
          `CONCAT(modified_by.fname, ' ', modified_by.lname, ' - ', modified_by.employeeCode)`,
          'name',
        )
        .andWhere('main.modified_by IS NOT NULL')
        .orderBy('modified_by.fname', 'ASC')
        .addOrderBy('modified_by.lname', 'ASC')
        .groupBy('modified_by.id');
    }

    if (association_type) {
      query.andWhere('main.association_type = :association_type', {
        association_type,
      });
    }

    return await query.getRawMany();
  }

  /**
   * View attachment files for a specific commission received record
   *
   * Retrieves all attachment files (payment proofs, receipts, bank statements)
   * associated with a commission received record
   *
   * @param id - Commission received record ID
   * @returns Commission received record with attachment files
   */
  async getAttachments(id: string): Promise<any> {
    return await this.vcReceivedRepo
      .createQueryBuilder('main')
      .select(['main.id', 'main.attachment_file'])
      .where('main.id = :id', { id })
      .orderBy('main.id', 'DESC')
      .getOne();
  }

  /**
   * Remove an attachment file from a commission received record
   *
   * Supports removal of attachment files with audit tracking
   * Also physically removes the file from storage
   *
   * @param params - Contains file information and target record ID
   * @param userData - Authenticated user information for audit tracking
   * @returns Removal result
   */
  async removeAttachments(
    params: RemoveAttachmentDto,
    userData: UserDataProps,
  ): Promise<any> {
    let repository;
    repository = this.vcReceivedRepo;

    // Get existing record
    const record = await repository
      .createQueryBuilder()
      .where('id = :id', { id: params.row_id })
      .getOne();

    // Check if record has attachments
    if (!record?.attachment_file?.length) return params;

    // Filter out the specified file
    const updatedAttachments = record.attachment_file.filter(
      (file: string) => file !== params.file_name,
    );

    // If file was found and removed, update the entity
    if (updatedAttachments.length !== record.attachment_file.length) {
      const entity = plainToInstance(VcmCommissionReceivedEntity, {
        attachment_file: updatedAttachments,
        modified_by_user: userData.id,
      });
      await repository.update({ id: params.row_id }, entity);

      // Physically remove the file from storage
      await this.fileService.removeFile(params.file_name);
    }

    return params;
  }

  /**
   * Add attachment files to a commission received record
   *
   * Supports file uploads for payment proofs and documentation
   *
   * @param params - Contains target record ID and file information
   * @param userData - Authenticated user information for audit tracking
   * @returns Addition result
   */
  async addAttachments(
    params: AddAttachmentDto,
    userData: UserDataProps,
  ): Promise<any> {
    let repository;

    repository = this.vcReceivedRepo;

    // Get existing record
    const record = await repository
      .createQueryBuilder()
      .where('id = :id', { id: params.id })
      .getOne();

    // Merge existing and new attachments
    const updatedAttachments = record.attachment_file
      ? [...record.attachment_file, ...params.attachment_file]
      : params.attachment_file;

    // Update record if there are new attachments
    if (updatedAttachments.length) {
      const entity = plainToInstance(VcmCommissionReceivedEntity, {
        attachment_file: updatedAttachments,
        modified_by_user: userData.id,
      });
      await repository.update({ id: params.id }, entity);
    }

    return params;
  }

  /**
   * Get detailed commission received information
   *
   * Retrieves complete commission received information including:
   * - Main payment details
   * - Related enquiry information
   * - Invoice information
   * - Payment mode and bank details
   *
   * @param params - Contains ID and association type
   * @returns Complete commission received information with case details
   */
  async findDetails(params: ReceivedInfoDto): Promise<any> {
    const query = this.vcReceivedRepo
      .createQueryBuilder('main')
      .select([
        'main.id',
        'main.association_type',
        'main.commission_enquiry_id',
        'main.total_amount',
        'main.currency',
        'main.conversion_rate',
        'main.total_amount_inr',
        'main.tax_details',
        'main.total_tax_amount',
        'main.other_deductions',
        'main.deduction_reason',
        'main.net_amount_inr',
        'main.payment_date',
        'main.payment_mode_id',
        'main.bank_account_id',
        'main.transaction_id',
        'main.attachment_file',
        'main.remarks',
        'main.by_user',
        'main.created',
        'main.modified_by_user',
        'main.modified',
        'mode.payment_mode_name',
        'bank.bank_name',
        'bank.acc_number',
        'bank.company_bank_address',
        'inv.invoice_no',
      ]);

    // Join invoice information
    query.leftJoin(
      'vcm_commission_invoice',
      'inv',
      'inv.enquiry_id = main.commission_enquiry_id AND inv.association_type = :association_type',
      { association_type: params.association_type },
    );

    // Add appropriate joins based on association type
    if (params.association_type === '1') {
      // Institute commission received details
      query
        .leftJoinAndSelect('main.institute_enquiry', 'enq')
        .addSelect([
          'visa_country.name',
          'client_country.name',
          'institute.institueName',
          'institute.UID',
          'intake.intakeyear',
          'intake.intakemonth',
        ])
        .leftJoin('enq.visa_country', 'visa_country')
        .leftJoin('enq.client_country', 'client_country')
        .leftJoin('enq.institute', 'institute')
        .leftJoin('enq.intake', 'intake');
    } else if (params.association_type === '2') {
      // Master agent commission received details
      query
        .leftJoinAndSelect('main.ma_enquiry', 'enq')
        .addSelect([
          'associate.masteragentName',
          'associate.uid',
          'visa_country.name',
          'client_country.name',
          'institute.institueName',
          'institute.UID',
          'intake.intakeyear',
          'intake.intakemonth',
        ])
        .leftJoin('enq.associate', 'associate')
        .leftJoin('enq.visa_country', 'visa_country')
        .leftJoin('enq.client_country', 'client_country')
        .leftJoin('enq.institute', 'institute')
        .leftJoin('enq.intake', 'intake');
    }

    // Add common joins
    query
      .leftJoin('main.mode', 'mode')
      .leftJoin('main.bank', 'bank')
      .where('main.association_type = :association_type', {
        association_type: Number(params.association_type),
      })
      .andWhere('main.commission_enquiry_id IS NOT NULL')
      .andWhere('main.id = :id', {
        id: Number(params.id),
      });

    const row = await query.getOne();

    if (!row) {
      return null;
    }

    // Get case details (line items)
    const caseDetails = await this.findDetailsById(params);
    (row as any).case_details = caseDetails;

    return row;
  }

  /**
   * Get commission received case details (line items)
   *
   * Retrieves per-case commission received details including:
   * - Tuition fees
   * - Commission amounts and percentages
   * - Student and case information
   * - Currency conversion details
   *
   * @param params - Contains commission received ID
   * @returns Commission received line items with detailed information
   */
  async findDetailsById(params: ReceivedInfoDto): Promise<any> {
    const query = this.redDetailRepo.createQueryBuilder('main');
    query
      .select([
        'main.visa_case_id AS visa_case_id',
        'main.tuition_fees AS tuition_fees',
        'main.ma_commission_type AS ma_commission_type',
        'main.ma_commission_percentage AS ma_commission_percentage',
        'main.ma_commission_amount AS ma_commission_amount',
        'main.our_commission_type AS our_commission_type',
        'main.our_commission_percentage AS our_commission_percentage',
        'main.our_commission_amount AS our_commission_amount',
        'main.our_commission_amount_inr AS our_commission_amount_inr',
        'main.currency As currency',
      ])
      .leftJoin('vms_visa_cases', 'vc', 'main.visa_case_id = vc.id')
      .addSelect(['vc.case_uid AS case_uid'])
      .leftJoin('students', 's', 'vc.student_id = s.id')
      .addSelect([
        's.fname AS fname',
        's.lname AS lname',
        's.UID AS UID',
        's.UID AS student_uid',
      ])
      .where('main.commission_received_id =:id', { id: params.id })
      .orderBy('main.id', 'ASC');

    return await query.getRawMany();
  }
}
