import {
  Body,
  Controller,
  Get,
  Post,
  UploadedFiles,
  UseGuards,
  UseInterceptors,
  ValidationPipe,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { VisaCommissionEnquiryService } from './visa-commission-enquiry.service';
import { SearchVisaCountriesDto } from './dto/search-visa-countries-dto';
import { SearchAssociatesDto } from './dto/search-associates-dto';
import { CreateCommissionEnquiryDto } from './dto/create.dto';
import { SearchDto } from './dto/search-dto';
import { FetchByUsersDto } from './dto/fetch-by-users.dto';
import { handleServiceRequest } from 'src/utils/response/response-handler';
import { SessionGuard } from 'src/config/guards/session.guard';
import { FetchByAssociationTypesDto } from './dto/fetch-by-association-types.dto';
import { SearchInstitutesDto } from './dto/search-institutes-dto';
import { SearchIntakesDto } from './dto/search-intakes-dto';
import { SearchCommissionInstancesDto } from './dto/search-commission-instances-dto';
import { SearchVisaCasesDto } from './dto/search-visa-cases-dto';
import { SearchCaseTuitionFeeDto } from './dto/search-case-tuition-fee-dto';
import { UpdateReceivedStatusDto } from './dto/update-received-status.dto';
import { CreateResponseDto } from './dto/create-response.dto';
import { CommissionReceivedDto } from './dto/create-received.dto';
import { CreateMaCommissionEnquiryDto } from './dto/create-ma.dto';
import { AnyFileUpload } from 'src/interceptors/file-upload.interceptor';
import { CreateMaResponseDto } from './dto/create-ma-response.dto';
import {
  UserData,
  UserDataProps,
} from 'src/utils/decorators/user-data.decorator';
import { SearchCaseCommissionReceivedInfoDto } from './dto/search-case-commission-received-info-dto';

type MulterFile = Express.Multer.File;

/**
 * VisaCommissionEnquiryController - REST API controller for commission enquiry management
 *
 * This controller handles all HTTP endpoints related to commission enquiries for visa cases.
 * It supports two main association types:
 * 1. Institute-based enquiries (Association Type 1)
 * 2. Master Agent-based enquiries (Association Type 2)
 *
 * The controller provides comprehensive functionality including:
 * - Commission enquiry creation and management
 * - Response handling for institutes and agents
 * - Commission receipt tracking
 * - Reference data endpoints for dropdowns
 * - File uploads for supporting documentation
 *
 * API Design Principles:
 * - Consistent POST endpoints for data retrieval with filters
 * - Separation of institute vs master agent workflows
 * - File upload support for documentation
 * - User authentication and session management
 * - Comprehensive search and filtering capabilities
 *
 * Security: Protected by SessionGuard for user authentication
 */
@ApiTags('Visa Commission Enquiry') // Swagger API documentation grouping
@Controller('') // Root path controller
// @UseGuards(AuthGuard) // Alternative authentication guard (commented out)
// @ApiBearerAuth('defaultBearerAuth') // Swagger authentication documentation
@UseGuards(SessionGuard) // Session-based authentication guard
export class VisaCommissionEnquiryController {
  constructor(
    private readonly vcEnquiryService: VisaCommissionEnquiryService,
  ) {}

  /**
   * Get all commission enquiries with advanced filtering
   *
   * POST endpoint for paginated search with multiple filter criteria
   *
   * @param searchDto - Comprehensive search parameters including:
   *   - Pagination (page, per_page)
   *   - Date range filters
   *   - Association type filtering
   *   - Status filtering
   *   - Text search
   *
   * @returns Paginated list of commission enquiries
   */
  @Post('all')
  async findAllInstituteCommissions(
    @Body() searchDto: SearchDto,
  ): Promise<any> {
    return await handleServiceRequest(this.vcEnquiryService.findAll(searchDto));
  }

  /**
   * Get specific commission enquiry by ID with detailed information
   *
   * @param searchDto - Contains enquiry ID for lookup
   * @returns Detailed commission enquiry information
   */
  @Post('enquiry-by-id')
  async findEnquiryById(@Body() searchDto: SearchDto): Promise<any> {
    return await handleServiceRequest(this.vcEnquiryService.findOne(searchDto));
  }

  /**
   * Get visa service countries for a specific visa product
   *
   * Used for dropdown population in commission enquiry forms
   *
   * @param params - Contains product_id for filtering
   * @returns List of countries where the visa service is offered
   */
  @Post('visa-service-countries')
  async getVisaServiceCountries(
    @Body(new ValidationPipe()) params: SearchVisaCountriesDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.getVisaCountryList(params.product_id),
    );
  }

  /**
   * Get list of associates (master agents or sub-agents)
   *
   * Used for commission enquiry assignment and filtering
   *
   * @param params - Search parameters including association type
   * @returns List of associates with formatted names
   */
  @Post('associate-list')
  async getAssociates(@Body(new ValidationPipe()) params: SearchAssociatesDto) {
    return await handleServiceRequest(
      this.vcEnquiryService.getAssociateList(params),
    );
  }

  /**
   * Get list of institutes (colleges/universities)
   *
   * Used for institute-based commission enquiries
   *
   * @param params - Search parameters for institute filtering
   * @returns List of institutes with formatted names
   */
  @Post('institute-list')
  async getInstitutes(@Body(new ValidationPipe()) params: SearchInstitutesDto) {
    return await handleServiceRequest(
      this.vcEnquiryService.getInstituteList(params),
    );
  }

  /**
   * Get list of all active client countries
   *
   * Used for commission calculation based on student nationality
   *
   * @returns List of all active countries
   */
  @Get('client-countries')
  async getClientCountries() {
    return await handleServiceRequest(
      this.vcEnquiryService.getClientCountryList(),
    );
  }

  /**
   * Get predefined response reasons for commission enquiries
   *
   * Used when responding to commission enquiries with standardized reasons
   *
   * @returns List of response reason options
   */
  @Get('response-reasons')
  async getResponseReasons() {
    return await handleServiceRequest(
      this.vcEnquiryService.getResponseReasonList(),
    );
  }

  /**
   * Get predefined difference reasons for commission enquiries
   *
   * Used when explaining differences between expected and actual commissions
   *
   * @returns List of difference reason options
   */
  @Get('difference-reasons')
  async getDifferenceReasons() {
    return await handleServiceRequest(
      this.vcEnquiryService.getDifferenceReasonList(),
    );
  }

  /**
   * Get intake periods for commission enquiries
   *
   * Used for filtering and reporting by academic intake periods
   *
   * @param params - Search parameters including institute or associate filters
   * @returns List of intake periods
   */
  @Post('intake-list')
  async getIntakes(@Body(new ValidationPipe()) params: SearchIntakesDto) {
    return await handleServiceRequest(
      this.vcEnquiryService.getIntakeList(params),
    );
  }

  /**
   * Get commission instance details for commission calculation
   *
   * Used to retrieve specific commission tiers or structures
   *
   * @param params - Search parameters for commission instances
   * @returns List of commission instances with details
   */
  @Post('instance-list')
  async getCommissionInstances(
    @Body(new ValidationPipe()) params: SearchCommissionInstancesDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.getCommissionInstanceList(params),
    );
  }

  /**
   * Get visa cases for commission enquiry creation
   *
   * Used to select specific visa cases when creating commission enquiries
   *
   * @param params - Search parameters for visa cases
   * @returns List of visa cases eligible for commission enquiries
   */
  @Post('case-list')
  async getVisaCases(@Body(new ValidationPipe()) params: SearchVisaCasesDto) {
    return await handleServiceRequest(
      this.vcEnquiryService.getVisaCaseList(params),
    );
  }

  /**
   * Get tuition fee information for specific visa cases
   *
   * Used for commission calculations based on tuition fees
   *
   * @param params - Search parameters for case tuition fees
   * @returns Tuition fee details for specified cases
   */
  @Post('case-tuition-fee-list')
  async getCaseTuitionFee(
    @Body(new ValidationPipe()) params: SearchCaseTuitionFeeDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.getCaseTuitionFeeList(params),
    );
  }

  /**
   * Create a new commission enquiry
   *
   * Supports both institute and master agent commission enquiries
   * Uses polymorphic DTO handling based on association type
   *
   * @param params - Commission enquiry data
   * @param userData - Authenticated user information
   * @returns Created commission enquiry
   */
  @Post('save-commission-enquiry')
  async storeCommissionEnquiry(
    @Body(new ValidationPipe())
    params: CreateCommissionEnquiryDto | CreateMaCommissionEnquiryDto,
    @UserData() userData: UserDataProps,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.create(params, userData.id),
    );
  }

  /**
   * Edit an existing commission enquiry
   *
   * @param params - Updated commission enquiry data
   * @param userData - Authenticated user information
   * @returns Updated commission enquiry
   */
  @Post('edit-commission-enquiry')
  async editCommissionEnquiry(
    @Body(new ValidationPipe())
    params: CreateCommissionEnquiryDto | CreateMaCommissionEnquiryDto,
    @UserData() userData: UserDataProps,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.update(params, userData.id),
    );
  }

  /**
   * Get distinct visa service countries by association type
   *
   * Used for filter dropdowns in search interfaces
   *
   * @param params - Contains association type for filtering
   * @returns Distinct visa service countries for the association type
   */
  @Post('fetch-service-countries')
  async getServiceCountriesByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchServiceCountriesByList(params.type),
    );
  }

  /**
   * Get distinct client countries by association type
   *
   * Used for filter dropdowns in search interfaces
   *
   * @param params - Contains association type for filtering
   * @returns Distinct client countries for the association type
   */
  @Post('fetch-client-countries')
  async getClientCountriesByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchClientCountriesByList(params.type),
    );
  }

  /**
   * Get distinct institutes by association type
   *
   * Used for filter dropdowns in search interfaces
   *
   * @param params - Contains association type for filtering
   * @returns Distinct institutes for the association type
   */
  @Post('fetch-institutes')
  async getInstitutesByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchInstitutesByList(params.type),
    );
  }

  /**
   * Get distinct associates for filter dropdowns
   *
   * @returns Distinct associates for all association types
   */
  @Get('fetch-associates')
  async getAssociatesByList() {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchAssociatesByList(),
    );
  }

  /**
   * Get distinct intakes by association type
   *
   * @param params - Contains association type for filtering
   * @returns Distinct intake periods for the association type
   */
  @Post('fetch-intakes')
  async getIntakesByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchIntakesByList(params.type),
    );
  }

  /**
   * Get distinct commission instances by association type
   *
   * @param params - Contains association type for filtering
   * @returns Distinct commission instances for the association type
   */
  @Post('fetch-instances')
  async getInstancesByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchInstancesByList(params.type),
    );
  }

  /**
   * Get distinct invoice branches by association type
   *
   * Used for invoicing and financial reporting
   *
   * @param params - Contains association type for filtering
   * @returns Distinct invoice branches for the association type
   */
  @Post('fetch-invoice-branches')
  async getInvoiceBranchByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchInvoiceBranchesByList(params.type),
    );
  }

  /**
   * Get distinct invoice bank accounts by association type
   *
   * Used for payment processing and reconciliation
   *
   * @param params - Contains association type for filtering
   * @returns Distinct invoice bank accounts for the association type
   */
  @Post('fetch-invoice-bank-accounts')
  async getInvoiceBankAccountsByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchInvoiceBankAccountsByList(params.type),
    );
  }

  /**
   * Get distinct users who created or updated enquiries
   *
   * Used for audit trail and filtering by user
   *
   * @param params - Contains filter type ('created_by' or 'updated_by') and association type
   * @returns Distinct users with formatted names
   */
  @Post('fetch-users')
  async getCreatedByOrUpdatedByUsers(
    @Body(new ValidationPipe()) params: FetchByUsersDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchCreatedByOrUpdatedByUsers(
        params.by,
        params.type,
      ),
    );
  }

  /**
   * Get detailed commission enquiry information by ID
   *
   * @param body - Contains enquiry ID and optional additional parameters
   * @returns Complete commission enquiry details
   */
  @Post('details-by-id')
  async getDetailsById(
    @Body(new ValidationPipe()) body: Record<string, string>,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.findDetailsById(body.id, body),
    );
  }

  /**
   * Get all invoice branches for dropdowns
   *
   * @returns Complete list of invoice branches
   */
  @Get('invoice-branches')
  async getInvoiceBranches() {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchInvoiceBranches(),
    );
  }

  /**
   * Get all invoice bank accounts for dropdowns
   *
   * @returns Complete list of invoice bank accounts
   */
  @Get('invoice-bank-accounts')
  async getInvoiceBankAccounts() {
    return await handleServiceRequest(
      this.vcEnquiryService.fetchInvoiceBankAccounts(),
    );
  }

  /**
   * Update commission received status
   *
   * Used to mark commissions as received, partially received, or pending
   *
   * @param body - Contains status update information
   * @param userData - Authenticated user information
   * @returns Update result
   */
  @Post('update-received-status')
  async updateReceivedStatus(
    @Body(new ValidationPipe()) body: UpdateReceivedStatusDto,
    @UserData() userData: UserDataProps,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.updateReceivedStatus(body, userData.id),
    );
  }

  /**
   * Save response to a commission enquiry
   *
   * Handles responses for both institute and master agent enquiries
   * Uses different DTOs and service methods based on association type
   *
   * @param body - Response data including reason and notes
   * @param userData - Authenticated user information
   * @returns Saved response information
   */
  @Post('save-response')
  async saveResponse(
    @Body(new ValidationPipe()) body: CreateResponseDto | CreateMaResponseDto,
    @UserData() userData: UserDataProps,
  ) {
    // Route to appropriate service method based on association type
    if (body.association_type === '1') {
      // Institute-based response
      return await handleServiceRequest(
        this.vcEnquiryService.saveResponse(body, userData.id),
      );
    } else {
      // Master agent-based response
      return await handleServiceRequest(
        this.vcEnquiryService.saveResponseMasterAgent(body, userData.id),
      );
    }
  }

  /**
   * Save commission received information with file attachments
   *
   * Supports file uploads for payment proofs, receipts, and documentation
   * Uses file interceptor for handling uploaded files
   *
   * @param body - Commission received data
   * @param files - Uploaded file attachments
   * @param userData - Authenticated user information
   * @returns Saved commission received record
   */
  @Post('save-received')
  @UseInterceptors(AnyFileUpload()) // File upload interceptor
  async saveReceived(
    @Body(new ValidationPipe()) body: CommissionReceivedDto,
    @UploadedFiles() files: MulterFile[],
    @UserData() userData: UserDataProps,
  ) {
    // Extract filenames from uploaded files
    body.attachment_file = files?.map((file) => file.filename) || null;

    // Route to appropriate service method based on association type
    if (body.association_type === '1') {
      // Institute-based commission received
      return await handleServiceRequest(
        this.vcEnquiryService.saveReceived(body, userData.id),
      );
    } else {
      // Master agent-based commission received
      return await handleServiceRequest(
        this.vcEnquiryService.saveReceivedMasterAgent(body, userData.id),
      );
    }
  }

  /**
   * Get commission received information for specific visa cases
   *
   * Used for reconciliation and reporting
   *
   * @param params - Search parameters for commission received information
   * @returns Commission received details for specified cases
   */
  @Post('case-commission-received-info')
  async getCaseCommissionReceivedInfo(
    @Body(new ValidationPipe()) params: SearchCaseCommissionReceivedInfoDto,
  ) {
    return await handleServiceRequest(
      this.vcEnquiryService.getCaseCommissionReceivedInfo(params),
    );
  }
}
