import { Controller, Get, Post, Body, UseGuards, UseInterceptors, UploadedFile, UploadedFiles, Param, BadRequestException, Query, Delete, Res } from '@nestjs/common';
import { ImageHistoryService } from './image-history.service';
import { ApiBearerAuth, ApiBody, ApiTags, ApiConsumes } from '@nestjs/swagger';
import { ImageDto, ImageToImageDto, ImageUpscaleDto } from './image-history.validation';
import { GenerateImageService } from './services/generate-image.service';
import { CurrentUser } from 'src/common/decorators/user.decorator';
import { IFullUser } from '../users/users.interface';
import { JwtAuthGuard } from 'src/guards/jwt-auth.guard';
import { Roles } from 'src/common/decorators/roles.decorator';
import { USER_ROLE } from '../users/users.constant';
import { RolesGuard } from 'src/guards/roles.guard';
import { ResponseMessage } from 'src/common/decorators/response_message.decorator';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import fs from 'node:fs';
import sharp from 'sharp';
import { IMAGE_GENERATION_ERROR_CAUSE } from './image-history.constant';
import { Response } from 'express';
import { DebugEventsService } from '../debug-events/debug-events.service';

@ApiTags('Image Endpoints')
@Controller('image')
@ApiBearerAuth()
export class ImageHistoryController {

	constructor(
		private readonly imageHistoryService: ImageHistoryService,
		private readonly generateImageService: GenerateImageService,
		private readonly debugEvents: DebugEventsService,
	) { }

	@Get('proxy')
	@UseGuards(JwtAuthGuard, RolesGuard)
	@Roles(USER_ROLE.user, USER_ROLE.admin, USER_ROLE.super_admin)
	async proxyImage(@Query('url') url: string, @Res() res: Response) {
		if (!url) throw new BadRequestException('url query param is required');

		// Whitelist trusted hosts to avoid SSRF
		const allowedHosts = ['cdn.binaplus.co.il', 'storage.googleapis.com', 'replicate.delivery', 'pbxt.replicate.delivery'];
		let parsed: URL;
		try { parsed = new URL(url); } catch { throw new BadRequestException('Invalid URL'); }
		if (!allowedHosts.some(h => parsed.hostname === h || parsed.hostname.endsWith('.' + h))) {
			throw new BadRequestException(`Host '${parsed.hostname}' not allowed`);
		}

		try {
			const upstream = await fetch(url);
			if (!upstream.ok) throw new BadRequestException(`Upstream returned ${upstream.status}`);
			const ct = upstream.headers.get('content-type') || 'image/png';
			res.setHeader('Content-Type', ct);
			res.setHeader('Cache-Control', 'public, max-age=86400');
			const buffer = Buffer.from(await upstream.arrayBuffer());
			res.send(buffer);
		} catch (e) {
			throw new BadRequestException(`Proxy fetch failed: ${(e as Error).message}`);
		}
	}

	@Get('get-all-images')
	@UseGuards(JwtAuthGuard, RolesGuard)
	@Roles(USER_ROLE.user, USER_ROLE.admin, USER_ROLE.super_admin)
	@ResponseMessage('Image history fetched successfully')
	async findAll(
		@CurrentUser() user: IFullUser,
		@Query() query: Record<string, any>
	) {
		query = { ...query, fields: 'images' }
		return this.imageHistoryService.findAllImageByUser(user, query);
	}


	@Get('get-generated-images')
	@UseGuards(JwtAuthGuard, RolesGuard)
	@Roles(USER_ROLE.super_admin)
	@ResponseMessage('Image history fetched successfully')
	async findAllImages(
		@Query() query: Record<string, any>
	) {
		return this.imageHistoryService.findAllImagesForAdmin(query);
	}

	@Get('get-image/:id')
	@UseGuards(JwtAuthGuard, RolesGuard)
	@Roles(USER_ROLE.user, USER_ROLE.admin, USER_ROLE.super_admin)
	@ResponseMessage('Text to image history fetched successfully')
	async getTextToImage(
		@CurrentUser() user: IFullUser,
		@Param('id') id: string
	) {
		return this.imageHistoryService.findImageById(user, id);
	}

	@Post('generate-text-to-image')
	@UseGuards(JwtAuthGuard, RolesGuard)
	@Roles(USER_ROLE.user, USER_ROLE.admin, USER_ROLE.super_admin)
	@ApiBody({ type: ImageDto })
	@ResponseMessage('Image generating in progress')
	async generateImage(
		@Body() body: ImageDto,
		@CurrentUser() user: IFullUser,
		@Res() res: Response
	) {
		try {
			await this.debugEvents.emit(user, {
				type: 'image:request_received',
				data: {
					model: body?.model,
					prompt: (body?.prompt || '').slice(0, 60),
					samples: body?.samples,
					style_preset: body?.style_preset,
					aspect_ratio: (body as any)?.aspect_ratio,
					mode: 'text-to-image',
				},
			});
			if (!body?.isExample) {
				return this.generateImageService.generateTextToImage(body, user, res);
			}
			else {
				return this.generateImageService.fakeTextToImage(body, user, res);
			}


		} catch (error) {
			throw error
		}

	}

	@Post('generate-image-to-image')
	@UseGuards(JwtAuthGuard, RolesGuard)
	@Roles(USER_ROLE.user, USER_ROLE.admin, USER_ROLE.super_admin)
	@ResponseMessage("Image generating in progress")
	@UseInterceptors(FilesInterceptor('files', 10))
	@ApiConsumes("multipart/form-data")
	@ApiBody({ type: ImageToImageDto })
	async imageToImage(
		@UploadedFiles() files: any[],
		@Body() body: ImageToImageDto,
		@CurrentUser() user: IFullUser,
		@Res() res: Response
	) {
		try {
			if (!files || files.length === 0) {
				throw new BadRequestException('At least one image file is required');
			}

			// Save files to local storage
			const filePaths: string[] = [];
			files.forEach((file, index) => {
				const filePath = `./temp-files/${Date.now()}_${index}_${file.originalname}`;
				try { 
					fs.writeFileSync(filePath, file.buffer); 
					filePaths.push(filePath);
				} catch (error) { 
					console.error(`Failed to save file ${index}:`, error);
				}
			});

			if (filePaths.length === 0) {
				throw new BadRequestException('Failed to save image files');
			}

			return await this.generateImageService.generateImageToImage({
				filePaths: filePaths,
				prompt: body.prompt,
				samples: body?.samples,
				style_preset: body?.style_preset,
				model: body?.model,
			}, user, res);
		} catch (error) {
			throw error;
		}
	}

	// @Post('upscale-image')
	// @UseGuards(JwtAuthGuard, RolesGuard)
	// @Roles(USER_ROLE.user, USER_ROLE.admin, USER_ROLE.super_admin)
	// @ResponseMessage("Image upscaling in progress")
	// @UseInterceptors(FileInterceptor('file'))
	// @ApiConsumes("multipart/form-data")
	// @ApiBody({ type: ImageUpscaleDto })
	// async upscaleImage(
	// 	@UploadedFile() file,
	// 	@Body() body: ImageUpscaleDto,
	// 	@CurrentUser() user: IFullUser,
	// 	@Res() res: Response
	// ) {
	// 	try {



	// 		// check file height and width (if less than 320px or greater than 1536px, return error) (stability check)
	// 		const image = await sharp(file.buffer).metadata();

	// 		// the max pixel count allowed by the upscaler (4194304) (double the height and width of the image)
	// 		if (((image.height * 2) * (image.width * 2)) > 4194304) {
	// 			throw new BadRequestException(`Upscaled image should not exceed ${4194304 / 2} (Height x Width) pixels`, {
	// 				cause: IMAGE_GENERATION_ERROR_CAUSE.MAX_PIXEL_LIMIT_UPSCALE
	// 			});
	// 		}

	// 		// save file to local storage
	// 		const filePath = `./temp-files/${file.originalname}`;
	// 		fs.writeFileSync(filePath, file.buffer);

	// 		return await this.generateImageService.upscaleImage({
	// 			filePath,
	// 			socketRoomId: body.socketRoomId,
	// 			...body
	// 		}, user, res);
	// 	} catch (error) {
	// 		throw error;
	// 	}
	// }

	@Delete('delete-image/:imageHistoryId/:imageId')
	@UseGuards(JwtAuthGuard, RolesGuard)
	@Roles(USER_ROLE.user, USER_ROLE.admin, USER_ROLE.super_admin)
	@ResponseMessage('Image deleted successfully')
	async deleteImage(
		@CurrentUser() user: IFullUser,
		@Param('imageHistoryId') imageHistoryId: string,
		@Param('imageId') imageId: string) {
		return this.imageHistoryService.deleteImageById(user, imageHistoryId, imageId);
	}

}
