import {
  Body,
  Controller,
  Get,
  Param,
  Post,
  UploadedFiles,
  UseGuards,
  UseInterceptors,
  ValidationPipe,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { VcCrudService } from '../services/crud.service';
import { handleServiceRequest } from 'src/utils/response/response-handler';
import { SessionGuard } from 'src/config/guards/session.guard';
import { AnyFileUpload } from 'src/interceptors/file-upload.interceptor';
import {
  UserData,
  UserDataProps,
} from 'src/utils/decorators/user-data.decorator';
import { SearchVisaCommissionDto } from '../dto/search-dto';
import { CountriesDetailsByIdsDto } from '../dto/countries-details-by-ids.dto';
import { CreateCommissionContractDto } from '../dto/create-commission-contract.dto';
import { RemoveAttachmentDto } from '../dto/remove-attachment.dto';
import { AddAttachmentDto } from '../dto/add-attachment.dto';
import { UpdateContractStatusDto } from '../dto/update-status.dto';

type MulterFile = Express.Multer.File;

@ApiTags('Visa Commission')
@Controller('')
@UseGuards(SessionGuard)
export class VcCrudController {
  constructor(private readonly visaCommissionService: VcCrudService) {}

  @Post('all')
  async findAllInstituteCommissions(
    @Body(new ValidationPipe()) searchDto: SearchVisaCommissionDto,
  ): Promise<any> {
    return await handleServiceRequest(
      this.visaCommissionService.findAll(searchDto),
    );
  }

  @Get('contract-info/:id')
  async getContractInfo(@Param('id') id: string) {
    return await handleServiceRequest(
      this.visaCommissionService.getContractInfo(id),
    );
  }

  @Post('save-commission-contract')
  @UseInterceptors(AnyFileUpload())
  async storeCommissionContract(
    @Body(new ValidationPipe()) params: CreateCommissionContractDto,
    @UploadedFiles() files: Express.Multer.File[],
    @UserData() userData: UserDataProps,
  ) {
    const generalContracts = files.filter((f) =>
      f.fieldname.startsWith('general_contracts'),
    );
    params.attachment_file =
      generalContracts.length > 0
        ? generalContracts.map((f) => f.filename)
        : null;

    const specificContracts = files.filter((f) =>
      f.fieldname.includes('specific_contract'),
    );

    specificContracts.forEach((file) => {
      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);

        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;
        }

        if (
          !params.applicable_sets[applicableSetIdx].sets[setIdx]
            .specific_contract
        ) {
          params.applicable_sets[applicableSetIdx].sets[
            setIdx
          ].specific_contract = [];
        }

        params.applicable_sets[applicableSetIdx].sets[
          setIdx
        ].specific_contract.push(file.filename);
      }
    });

    return await handleServiceRequest(
      this.visaCommissionService.createCommission(params, userData),
    );
  }

  @Post('edit-commission-contract')
  async editCommissionContract(
    @Body(new ValidationPipe()) params: CreateCommissionContractDto,
    @UserData() userData: UserDataProps,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.editCommission(params, userData),
    );
  }

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

  @Post('remove-attachment')
  async removeContractAttachments(
    @Body(new ValidationPipe()) attachment: RemoveAttachmentDto,
    @UserData() userData: UserDataProps,
  ) {
    return await handleServiceRequest(
      this.visaCommissionService.removeContractAttachments(
        attachment,
        userData,
      ),
    );
  }

  @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),
    );
  }

  @Get('contract-edit-history/:id')
  async getContractEditHistory(@Param('id') contractId: string) {
    return await handleServiceRequest(
      this.visaCommissionService.getContractEditHistoryWithLabels(contractId),
    );
  }

  @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')
  async getContractSetDetailsById(@Param('id') id: string) {
    return await handleServiceRequest(
      this.visaCommissionService.getContractSetDetailsById(id),
    );
  }
}
