import { Controller, Post, Logger, BadRequestException, UploadedFile, UseInterceptors, Res, Get, UseGuards } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ImportCSVService } from './csv-import.service';
import { ApiTags, ApiOperation, ApiResponse, ApiConsumes, ApiBody, ApiBearerAuth } from '@nestjs/swagger';
import { diskStorage } from 'multer';
import { extname } from 'path';
import * as fs from 'fs';
import { Response } from 'express';
import { JwtAuthGuard } from 'common/guards/jwt-auth.guard';
import { RolesGuard } from 'common/guards/roles.guard';
import { Roles } from 'common/decorators/role.decorator';
import { UserRole } from 'common/enum/UserRole.enum';

@Controller({ path: 'csv-import', version: '1' })
@ApiTags('CSV Import')
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBearerAuth()
@Roles(UserRole.ADMIN, UserRole.SUPER_ADMIN)
export class CsvImportController {
  private readonly logger = new Logger(CsvImportController.name);

  constructor(private readonly importCSVService: ImportCSVService) {}

  @Post('geo-names')
  @ApiOperation({ summary: 'Upload GeoNames CSV file for import' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    description: 'CSV file to be uploaded',
    type: 'string',
    schema: {
      type: 'object',
      properties: {
        file: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiResponse({ status: 200, description: 'File uploaded successfully, import queued' })
  @ApiResponse({ status: 400, description: 'Invalid file or format' })
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads',
        filename: (req, file, cb) => {
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          const fileExt = extname(file.originalname);
          cb(null, `geonames-${uniqueSuffix}${fileExt}`);
        },
      }),
      fileFilter: (req, file, cb) => {
        if (file.mimetype !== 'text/csv' && !file.originalname.endsWith('.csv')) {
          return cb(new BadRequestException('Only CSV files are allowed'), false);
        }
        cb(null, true);
      },
    }),
  )
  async uploadGeoNames(@UploadedFile() file: Express.Multer.File, @Res() res: Response) {
    if (!file) {
      throw new BadRequestException('CSV file is required');
    }

    this.logger.log(`Received GeoNames CSV file: ${file.originalname}, size: ${file.size} bytes`);

    try {
      // Immediately respond to the client that file is uploaded
      res.status(200).json({
        message: 'File uploaded successfully',
        filename: file.filename,
        originalFilename: file.originalname,
        importStatus: 'QUEUED',
      });

      // Trigger background import process
      this.backgroundImportGeoNames(file);
    } catch (error) {
      // If there's an error during initial upload, delete the file
      if (file && file.path) {
        fs.unlink(file.path, () => {});
      }
      throw error;
    }
  }

  // Background import method
  private async backgroundImportGeoNames(file: Express.Multer.File) {
    try {
      await this.importCSVService.importGeoNames(file.path);
    } catch (error) {
      // Log import errors
      this.logger.error(`GeoNames import failed for file: ${file.originalname}`, error);
      fs.unlink(file.path, () => {});
    }
  }

  // Similar approach for City Blocks import
  @Post('city-blocks-ipv4')
  @ApiOperation({ summary: 'Upload City Blocks CSV file for import' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    description: 'CSV file to be uploaded',
    type: 'string',
    schema: {
      type: 'object',
      properties: {
        file: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiResponse({ status: 200, description: 'File uploaded successfully, import queued' })
  @ApiResponse({ status: 400, description: 'Invalid file or format' })
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads',
        filename: (req, file, cb) => {
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          const fileExt = extname(file.originalname);
          cb(null, `cityblocks-${uniqueSuffix}${fileExt}`);
        },
      }),
      fileFilter: (req, file, cb) => {
        if (file.mimetype !== 'text/csv' && !file.originalname.endsWith('.csv')) {
          return cb(new BadRequestException('Only CSV files are allowed'), false);
        }
        cb(null, true);
      },
    }),
  )
  async uploadCityBlocksIpv4(@UploadedFile() file: Express.Multer.File, @Res() res: Response) {
    if (!file) {
      throw new BadRequestException('CSV file is required');
    }

    this.logger.log(`Received City Blocks CSV file: ${file.originalname}, size: ${file.size} bytes`);

    try {
      // Immediately respond to the client that file is uploaded
      res.status(200).json({
        message: 'File uploaded successfully',
        filename: file.filename,
        originalFilename: file.originalname,
        importStatus: 'QUEUED',
      });

      this.backgroundImportCityBlocks(file);
    } catch (error) {
      // If there's an error during initial upload, delete the file
      if (file && file.path) {
        fs.unlink(file.path, () => {});
      }
      throw error;
    }
  }

  private async backgroundImportCityBlocks(file: Express.Multer.File) {
    try {
      await this.importCSVService.importCityBlocksIpv4(file.path);

      this.logger.log(`City Blocks import completed for file: ${file.originalname}`);
    } catch (error) {
      this.logger.error(`City Blocks import failed for file: ${file.originalname}`, error);

      fs.unlink(file.path, () => {});
    }
  }

  // Add asn import method
  @Post('asn')
  @ApiOperation({ summary: 'Upload ASN CSV file for import' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    description: 'CSV file to be uploaded',
    type: 'string',
    schema: {
      type: 'object',
      properties: {
        file: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiResponse({ status: 200, description: 'File uploaded successfully, import queued' })
  @ApiResponse({ status: 400, description: 'Invalid file or format' })
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads',
        filename: (req, file, cb) => {
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          const fileExt = extname(file.originalname);
          cb(null, `asn-${uniqueSuffix}${fileExt}`);
        },
      }),
      fileFilter: (req, file, cb) => {
        if (file.mimetype !== 'text/csv' && !file.originalname.endsWith('.csv')) {
          return cb(new BadRequestException('Only CSV files are allowed'), false);
        }
        cb(null, true);
      },
    }),
  )
  async uploadAsn(@UploadedFile() file: Express.Multer.File, @Res() res: Response) {
    if (!file) {
      throw new BadRequestException('CSV file is required');
    }

    this.logger.log(`Received ASN CSV file: ${file.originalname}, size: ${file.size} bytes`);

    try {
      res.status(200).json({
        message: 'File uploaded successfully',
        filename: file.filename,
        originalFilename: file.originalname,
        importStatus: 'QUEUED',
      });

      this.backgroundImportAsn(file);
    } catch (error) {
      if (file && file.path) {
        fs.unlink(file.path, () => {});
      }
      throw error;
    }
  }

  private async backgroundImportAsn(file: Express.Multer.File) {
    try {
      await this.importCSVService.importAsn(file.path);

      this.logger.log(`ASN import completed for file: ${file.originalname}`);
    } catch (error) {
      this.logger.error(`ASN import failed for file: ${file.originalname}`, error);

      fs.unlink(file.path, () => {});
    }
  }

  //  add for citiblocks ipv6
  @Post('city-blocks-ipv6')
  @ApiOperation({ summary: 'Upload City Blocks IPv6 CSV file for import' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    description: 'CSV file to be uploaded',
    type: 'string',
    schema: {
      type: 'object',
      properties: {
        file: {
          type: 'string',
          format: 'binary',
        },
      },
    },
  })
  @ApiResponse({ status: 200, description: 'File uploaded successfully, import queued' })
  @ApiResponse({ status: 400, description: 'Invalid file or format' })
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads',
        filename: (req, file, cb) => {
          const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
          const fileExt = extname(file.originalname);
          cb(null, `cityblocks-ipv6-${uniqueSuffix}${fileExt}`);
        },
      }),
      fileFilter: (req, file, cb) => {
        if (file.mimetype !== 'text/csv' && !file.originalname.endsWith('.csv')) {
          return cb(new BadRequestException('Only CSV files are allowed'), false);
        }
        cb(null, true);
      },
    }),
  )
  async uploadCityBlocksIpv6(@UploadedFile() file: Express.Multer.File, @Res() res: Response) {
    if (!file) {
      throw new BadRequestException('CSV file is required');
    }

    this.logger.log(`Received City Blocks IPv6 CSV file: ${file.originalname}, size: ${file.size} bytes`);

    try {
      res.status(200).json({
        message: 'File uploaded successfully',
        filename: file.filename,
        originalFilename: file.originalname,
        importStatus: 'QUEUED',
      });

      this.backgroundImportCityBlocksIpv6(file);
    } catch (error) {
      if (file && file.path) {
        fs.unlink(file.path, () => {});
      }
      throw error;
    }
  }

  private async backgroundImportCityBlocksIpv6(file: Express.Multer.File) {
    try {
      await this.importCSVService.importCityBlocksIpv6(file.path);

      this.logger.log(`City Blocks IPv6 import completed for file: ${file.originalname}`);
    } catch (error) {
      this.logger.error(`City Blocks IPv6 import failed for file: ${file.originalname}`, error);

      fs.unlink(file.path, () => {});
    }
  }

  @Post('auto-calculate-endip')
  @ApiOperation({ summary: 'Auto calculate end IP for IPv6' })
  @ApiResponse({ status: 200, description: 'End IP calculated successfully' })
  @ApiResponse({ status: 400, description: 'Error calculating end IP' })
  async autoCalculate() {
    const result = await this.importCSVService.autoCalculateIPv6EndIp();
    return { message: result };
  }

  @Post('populate-hash-ipv4')
  @ApiOperation({ summary: 'Populate hash for IPv4' })
  @ApiResponse({ status: 200, description: 'Hash populated successfully' })
  async populateHashIpv4() {
    await this.importCSVService.populateDataHashIPV4();
    return { message: 'Hash populated successfully' };
  }

  @Get('populate-hash-ipv6')
  @ApiOperation({ summary: 'Populate hash for IPv6' })
  @ApiResponse({ status: 200, description: 'Hash populated successfully' })
  @ApiResponse({ status: 400, description: 'Error populating hash' })
  async populateHashIpv6() {
    await this.importCSVService.populateDataHashIPV6();
    return { message: 'Hash populated successfully' };
  }

  @Get('populate-hash-asn')
  @ApiOperation({ summary: 'Populate hash for ASN' })
  @ApiResponse({ status: 200, description: 'Hash populated successfully' })
  @ApiResponse({ status: 400, description: 'Error populating hash' })
  async populateHashAsn() {
    await this.importCSVService.populateDataHashASN();
    return { message: 'Hash populated successfully' };
  }

  @Get('populate-hash-geonames')
  @ApiOperation({ summary: 'Populate hash for GeoNames' })
  @ApiResponse({ status: 200, description: 'Hash populated successfully' })
  @ApiResponse({ status: 400, description: 'Error populating hash' })
  async populateHashGeoNames() {
    await this.importCSVService.populateDataHashGeoName();
    return { message: 'Hash populated successfully' };
  }
}
