// Import necessary decorators and utilities from NestJS
import {
  Body,
  Controller,
  Get,
  Param,
  Post,
  UploadedFiles,
  UseGuards,
  UseInterceptors,
  ValidationPipe,
} from '@nestjs/common';

// Import Swagger decorator for API documentation
import { ApiTags } from '@nestjs/swagger';

// Import service containing business logic
import { VisaCommissionService } from './visa-commission.service';

// Import constants and DTOs (12+ different DTOs!)
import { VISA_PRODUCTS } from 'src/constants/visa/visa-commission';
import { SearchProductCountriesDto } from './dto/search-product-countries-dto';
import { SearchAssociatesDto } from './dto/search-associates-dto';
import { CreateCommissionContractDto } from './dto/create-commission-contract.dto';
import { SearchCollegeCampusDto } from './dto/search-college-campus-dto';
import { SearchVisaCommissionDto } from './dto/search-dto';
import { CountriesDetailsByIdsDto } from './dto/countries-details-by-ids.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-typs.dto';
import { SearchCollegeCampusCoursesDto } from './dto/search-college-campus-courses-dto';
import { AnyFileUpload } from 'src/interceptors/file-upload.interceptor';
import { RemoveAttachmentDto } from './dto/remove-attachment.dto';
import { AddAttachmentDto } from './dto/add-attachment.dto';
import { UpdateContractStatusDto } from './dto/update-status.dto';
import {
  UserData,
  UserDataProps,
} from 'src/utils/decorators/user-data.decorator';
import { CheckDuplicateContractDto } from './dto/check-duplicate-dto';

// Type alias for Multer file uploads
type MulterFile = Express.Multer.File;

/**
 * VisaCommissionController - Handles HTTP requests for comprehensive visa commission contract management
 *
 * This is one of the most complex controllers in the system, managing the complete lifecycle
 * of commission contracts for visa services. It includes sophisticated file handling,
 * multi-level contract structures, and comprehensive filtering capabilities.
 *
 * Business Context: Visa Commission Contract Management System
 * - Manages commission contracts with educational institutes and agents
 * - Handles complex multi-level contract structures with specific terms
 * - Manages contract attachments and documentation
 * - Tracks contract history and status changes
 * - Supports duplicate checking and validation
 *
 * Key Features:
 * - 28+ endpoints for comprehensive contract management
 * - Complex file upload handling with multi-level field mapping
 * - Contract history tracking and audit trails
 * - Duplicate contract validation
 * - Status management and workflow control
 * - Multi-association type support
 *
 * @ApiTags('Visa Commission') - Groups all endpoints in Swagger UI
 * @Controller('') - Base route for this controller
 * @UseGuards(SessionGuard) - Protects all endpoints with session authentication
 */
@ApiTags('Visa Commission')
@Controller('')
// @UseGuards(AuthGuard) - Commented out alternative authentication guard
// @ApiBearerAuth('defaultBearerAuth') - Commented out bearer auth documentation
@UseGuards(SessionGuard)
export class VisaCommissionController {
  /**
   * Constructor with dependency injection
   *
   * @param visaCommissionService - Injected service containing all commission contract business logic
   */
  constructor(private readonly visaCommissionService: VisaCommissionService) {}

  /**
   * POST /all-commissions - Retrieves paginated commission contracts with advanced filtering
   *
   * Main search endpoint for commission contract records.
   * Uses POST for complex search criteria.
   *
   * @param searchDto - Comprehensive search parameters for contract filtering
   * @returns Paginated list of commission contracts with metadata
   */
  @Post('all-commissions')
  async findAllInstituteCommissions(
    @Body() searchDto: SearchVisaCommissionDto,
  ): Promise<any> {
    return await handleServiceRequest(
      this.visaCommissionService.findAll(searchDto),
    );
  }

  /**
   * GET /contract-info/:id - Retrieves detailed information for a specific contract
   *
   * @param id - Contract ID
   * @returns Complete contract information with all related data
   */
  @Get('contract-info/:id')
  async getContractInfo(@Param('id') id: string) {
    return await handleServiceRequest(
      this.visaCommissionService.getContractInfo(id),
    );
  }

  /**
   * GET /visa-products-list - Retrieves visa product list
   *
   * Filtered to only show product with ID 8 (likely "Study Visa").
   * Hardcoded filtering suggests other products may be deprecated or not supported.
   *
   * @returns Filtered list of visa products
   */
  @Get('visa-products-list')
  getVisaProductList() {
    return VISA_PRODUCTS.filter((item) => item.id === 8);
  }

  /**
   * POST /visa-service-countries - Retrieves countries for specific visa products
   *
   * @param params - Contains product ID to filter countries
   * @returns List of countries where the visa product is available
   */
  @Post('visa-service-countries')
  async getVisaServiceCountries(
    @Body(new ValidationPipe()) params: SearchProductCountriesDto,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.getVisaCountryList(params.product_id),
    );
  }

  /**
   * POST /associate-list - Retrieves associates with filtering
   *
   * Associates = Educational institutes or master agents.
   *
   * @param params - Search parameters for associates
   * @returns Filtered list of associates
   */
  @Post('associate-list')
  async getAssociates(@Body(new ValidationPipe()) params: SearchAssociatesDto) {
    return await handleServiceRequest(
      this.visaCommissionService.getAssociateList(params),
    );
  }

  /**
   * GET /client-countries - Retrieves client countries
   *
   * Client countries = Countries where students/clients come from.
   *
   * @returns List of client countries
   */
  @Get('client-countries')
  async getClientCountries() {
    return await handleServiceRequest(
      this.visaCommissionService.getClientCountryList(),
    );
  }

  /**
   * POST /college-campus-list - Retrieves college campuses with filtering
   *
   * Used for selecting specific campuses of educational institutes.
   *
   * @param params - Search parameters for college campuses
   * @returns Filtered list of college campuses
   */
  @Post('college-campus-list')
  async getCollegeCampus(
    @Body(new ValidationPipe()) params: SearchCollegeCampusDto,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.getInstituteCampusList(params),
    );
  }

  /**
   * GET /study-level-list - Retrieves study levels
   *
   * Study levels = Academic levels (Undergraduate, Postgraduate, Diploma, etc.)
   *
   * @returns List of study levels
   */
  @Get('study-level-list')
  async getStudyLevels() {
    return await handleServiceRequest(
      this.visaCommissionService.getStudyLevelList(),
    );
  }

  /**
   * POST /c-d-b-ids - Retrieves country details by IDs
   *
   * Endpoint name appears to be abbreviated ("Countries Details By IDs").
   *
   * @param params - Contains array of country IDs
   * @returns Detailed information for specified countries
   */
  @Post('c-d-b-ids')
  async getCountriesDetailsByIds(
    @Body(new ValidationPipe()) params: CountriesDetailsByIdsDto,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.getCountriesByIds(params.countries),
    );
  }

  // ==================== COMPLEX FILE UPLOAD ENDPOINT ====================
  // This endpoint demonstrates sophisticated multi-file upload handling
  // with complex field mapping for contract document management

  /**
   * POST /save-commission-contract - Creates a new commission contract with complex file uploads
   *
   * This is one of the most complex endpoints in the system, handling:
   * - General contract documents
   * - Specific contract documents for multiple contract sets
   * - Complex field mapping with array indices
   * - Multi-level file organization
   *
   * File Structure:
   * 1. General contracts: files with fieldname starting with 'general_contracts'
   * 2. Specific contracts: files with fieldname pattern containing 'specific_contract'
   *
   * Fieldname Pattern for Specific Contracts:
   * applicable_sets[0][sets][0][specific_contract][0] = file
   * - First index: applicable set index
   * - Second index: set index within applicable set
   * - Third index: specific contract index within set
   *
   * This allows for multi-level contract document organization.
   */
  @Post('save-commission-contract')
  @UseInterceptors(AnyFileUpload()) // File upload interceptor
  async storeCommissionContract(
    @Body(new ValidationPipe()) params: CreateCommissionContractDto,
    @UploadedFiles() files: Express.Multer.File[], // All uploaded files
    @UserData() userData: UserDataProps, // User data from session
  ) {
    // 1. Process general contract files
    const generalContracts = files.filter((f) =>
      f.fieldname.startsWith('general_contracts'),
    );
    params.attachment_file =
      generalContracts.length > 0
        ? generalContracts.map((f) => f.filename)
        : null;

    // 2. Process specific contract files with complex field mapping
    const specificContracts = files.filter((f) =>
      f.fieldname.includes('specific_contract'),
    );

    // Map specific contract files to their respective positions in the contract structure
    specificContracts.forEach((file) => {
      // Parse complex fieldname pattern
      const match = file.fieldname.match(
        /applicable_sets\[(\d+)\]\[sets\]\[(\d+)\]\[specific_contract\]\[(\d+)\]/,
      );

      if (match) {
        const [_, applicableSetIdxStr, setIdxStr] = match;
        const applicableSetIdx = parseInt(applicableSetIdxStr, 10);
        const setIdx = parseInt(setIdxStr, 10);

        // Initialize nested arrays if they don't exist
        if (!params.applicable_sets[applicableSetIdx]) {
          params.applicable_sets[applicableSetIdx] = { sets: [] } as any;
        }
        if (!params.applicable_sets[applicableSetIdx].sets[setIdx]) {
          params.applicable_sets[applicableSetIdx].sets[setIdx] = {} as any;
        }

        // Initialize specific contract array
        if (
          !params.applicable_sets[applicableSetIdx].sets[setIdx]
            .specific_contract
        ) {
          params.applicable_sets[applicableSetIdx].sets[
            setIdx
          ].specific_contract = [];
        }

        // Add file to appropriate position
        params.applicable_sets[applicableSetIdx].sets[
          setIdx
        ].specific_contract.push(file.filename);
      }
    });

    // Pass to service for processing
    return await handleServiceRequest(
      this.visaCommissionService.createCommission(params, userData),
    );
  }

  /**
   * POST /edit-commission-contract - Updates an existing commission contract
   *
   * Note: This endpoint doesn't support file uploads for updates.
   * File attachments must be managed separately via add/remove attachment endpoints.
   *
   * @param params - Validated contract update data
   * @param userData - Current user's data for audit trail
   * @returns Updated contract
   */
  @Post('edit-commission-contract')
  async editCommissionContract(
    @Body(new ValidationPipe()) params: CreateCommissionContractDto,
    @UserData() userData: UserDataProps,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.editCommission(params, userData),
    );
  }

  // ==================== FETCH BY LIST ENDPOINTS WITH TYPE FILTERING ====================

  /**
   * POST /fetch-service-countries - Distinct service countries by association type
   */
  @Post('fetch-service-countries')
  async getServiceCountriesByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.fetchServiceCountriesByList(params.type),
    );
  }

  /**
   * POST /fetch-client-countries - Distinct client countries by association type
   */
  @Post('fetch-client-countries')
  async getClientCountriesByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.fetchClientCountriesByList(params.type),
    );
  }

  /**
   * POST /fetch-institutes - Distinct institutes by association type
   */
  @Post('fetch-institutes')
  async getInstitutesByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.fetchInstitutesByList(params.type),
    );
  }

  /**
   * POST /fetch-associates - Distinct associates by association type
   */
  @Post('fetch-associates')
  async getAssociatesByList(
    @Body(new ValidationPipe()) params: FetchByAssociationTypesDto,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.fetchAssociatesByList(params.type),
    );
  }

  /**
   * POST /fetch-users - Distinct users by activity and association type
   */
  @Post('fetch-users')
  async getCreatedByOrUpdatedByUsers(
    @Body(new ValidationPipe()) params: FetchByUsersDto,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.fetchCreatedByOrUpdatedByUsers(
        params.by,
        params.type,
      ),
    );
  }

  /**
   * POST /fetch-courses-by-campus-study-levels - Complex course filtering
   *
   * Multi-dimensional filtering for courses based on:
   * - Institute campus
   * - Study levels
   * - Other criteria
   *
   * @param searchCoursesDto - Multi-dimensional search parameters
   * @returns Filtered list of courses
   */
  @Post('fetch-courses-by-campus-study-levels')
  async getCoursesByInstituteCampusStudyLevels(
    @Body() searchCoursesDto: SearchCollegeCampusCoursesDto,
  ): Promise<any> {
    return await handleServiceRequest(
      this.visaCommissionService.getCoursesByInstituteCampusStudyLevels(
        searchCoursesDto,
      ),
    );
  }

  // ==================== CONTRACT ATTACHMENT MANAGEMENT ====================

  /**
   * GET /contract-attachments/:id - Retrieves attachments for a specific contract
   */
  @Get('contract-attachments/:id')
  async getContractAttachments(@Param('id') id: string) {
    return await handleServiceRequest(
      this.visaCommissionService.getContractAttachments(id),
    );
  }

  /**
   * POST /remove-attachment - Removes an attachment from a contract
   */
  @Post('remove-attachment')
  async removeContractAttachments(
    @Body(new ValidationPipe()) attachment: RemoveAttachmentDto,
    @UserData() userData: UserDataProps,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.removeContractAttachments(
        attachment,
        userData,
      ),
    );
  }

  /**
   * POST /add-attachment - Adds new attachments to an existing contract
   */
  @Post('add-attachment')
  @UseInterceptors(AnyFileUpload())
  async addContractAttachments(
    @Body(new ValidationPipe()) body: AddAttachmentDto,
    @UploadedFiles() files: MulterFile[],
    @UserData() userData: UserDataProps,
  ) {
    body.attachment_file = files?.map((file) => file.filename) || null;
    return await handleServiceRequest(
      this.visaCommissionService.addContractAttachments(body, userData),
    );
  }

  // ==================== CONTRACT HISTORY AND STATUS MANAGEMENT ====================

  /**
   * GET /contract-edit-history/:id - Retrieves edit history for a contract
   *
   * Includes labels/mapping for human-readable display.
   *
   * @param contractId - Contract ID
   * @returns Contract edit history with labels
   */
  @Get('contract-edit-history/:id')
  async getContractEditHistory(@Param('id') contractId: string) {
    return await handleServiceRequest(
      this.visaCommissionService.getContractEditHistoryWithLabels(contractId),
    );
  }

  /**
   * POST /update-status - Updates contract status
   *
   * Used for workflow management (e.g., draft → active → expired).
   *
   * @param body - Status update data
   * @param userData - Current user's data for audit trail
   * @returns Status update result
   */
  @Post('update-status')
  async updateContractStatus(
    @Body(new ValidationPipe()) body: UpdateContractStatusDto,
    @UserData() userData: UserDataProps,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.updateContractStatus(userData.id, body),
    );
  }

  /**
   * GET /contract-set-details-by-id/:id - Retrieves details for a specific contract set
   *
   * Contract sets = Groups of contract terms/conditions.
   *
   * @param id - Contract set ID
   * @returns Detailed contract set information
   */
  @Get('contract-set-details-by-id/:id')
  async getContractSetDetailsById(@Param('id') id: string) {
    return await handleServiceRequest(
      this.visaCommissionService.getContractSetDetailsById(id),
    );
  }

  /**
   * POST /check-duplicate - Checks for duplicate contracts
   *
   * Business validation to prevent duplicate contract creation.
   * Checks based on multiple criteria (associate, product, countries, etc.).
   *
   * @param params - Contract parameters to check for duplicates
   * @returns Duplicate check result
   */
  @Post('check-duplicate')
  async checkDuplicateContract(
    @Body(new ValidationPipe()) params: CheckDuplicateContractDto,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.checkDuplicateContract(params),
    );
  }
}
