import {
  Controller,
  Get,
  Post,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  Request,
  ParseIntPipe,
  Res,
  HttpException,
  HttpStatus,
  Logger,
} from '@nestjs/common';
import { Response } from 'express';
import axios from 'axios';
import AdmZip from 'adm-zip';
import { AI3DService } from './ai-3d.service';
import { CreateTaskDto } from './dto/create-task.dto';
import { QueryTaskDto } from './dto/query-task.dto';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { CurrentTenantId } from '../auth/decorators/current-tenant-id.decorator';
import { Public } from '../auth/decorators/public.decorator';

@Controller('ai-3d')
@UseGuards(JwtAuthGuard)
export class AI3DController {
  private readonly logger = new Logger(AI3DController.name);

  constructor(private readonly ai3dService: AI3DService) {}

  /**
   * 创建生成任务
   * POST /api/ai-3d/generate
   */
  @Post('generate')
  createTask(
    @Body() createTaskDto: CreateTaskDto,
    @CurrentTenantId() tenantId: number,
    @Request() req,
  ) {
    const userId = req?.user?.userId;
    return this.ai3dService.createTask(userId, tenantId, createTaskDto);
  }

  /**
   * 获取任务列表
   * GET /api/ai-3d/tasks
   */
  @Get('tasks')
  getTasks(@Query() queryDto: QueryTaskDto, @Request() req) {
    const userId = req?.user?.userId;
    return this.ai3dService.getTasks(userId, queryDto);
  }

  /**
   * 获取任务详情
   * GET /api/ai-3d/tasks/:id
   */
  @Get('tasks/:id')
  getTask(@Param('id', ParseIntPipe) id: number, @Request() req) {
    const userId = req?.user?.userId;
    return this.ai3dService.getTask(userId, id);
  }

  /**
   * 重试任务
   * POST /api/ai-3d/tasks/:id/retry
   */
  @Post('tasks/:id/retry')
  retryTask(@Param('id', ParseIntPipe) id: number, @Request() req) {
    const userId = req?.user?.userId;
    return this.ai3dService.retryTask(userId, id);
  }

  /**
   * 删除任务
   * DELETE /api/ai-3d/tasks/:id
   */
  @Delete('tasks/:id')
  deleteTask(@Param('id', ParseIntPipe) id: number, @Request() req) {
    const userId = req?.user?.userId;
    return this.ai3dService.deleteTask(userId, id);
  }

  /**
   * 代理模型文件（解决CORS问题）
   * GET /api/ai-3d/proxy-model
   */
  @Get('proxy-model')
  @Public() // 允许公开访问，因为模型URL已经包含签名
  async proxyModel(@Query('url') url: string, @Res() res: Response) {
    if (!url) {
      throw new HttpException('URL参数不能为空', HttpStatus.BAD_REQUEST);
    }

    this.logger.log(`[proxy-model] 开始处理请求，URL长度: ${url.length}`);

    try {
      // URL解码（处理URL编码）
      let decodedUrl: string;
      try {
        decodedUrl = decodeURIComponent(url);
        this.logger.log(`[proxy-model] URL解码成功`);
      } catch (e) {
        // 如果解码失败，使用原始URL
        decodedUrl = url;
        this.logger.warn(`[proxy-model] URL解码失败，使用原始URL`);
      }

      // 验证URL是否为腾讯云COS链接（安全验证）
      if (
        !decodedUrl.includes('tencentcos.cn') &&
        !decodedUrl.includes('qcloud.com')
      ) {
        throw new HttpException(
          '不支持的URL来源，仅支持腾讯云COS链接',
          HttpStatus.BAD_REQUEST,
        );
      }

      // 验证URL格式
      try {
        new URL(decodedUrl);
      } catch (e) {
        throw new HttpException('URL格式无效', HttpStatus.BAD_REQUEST);
      }

      this.logger.log(`[proxy-model] 开始下载文件...`);

      // 从源URL获取文件
      const response = await axios.get(decodedUrl, {
        responseType: 'arraybuffer', // 使用arraybuffer以便处理ZIP
        timeout: 120000, // 120秒超时（ZIP文件可能较大）
        maxContentLength: 100 * 1024 * 1024, // 最大100MB
        headers: {
          'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
          Accept: '*/*',
        },
      });

      this.logger.log(
        `[proxy-model] 文件下载成功，大小: ${response.data.byteLength} bytes`,
      );

      let fileData: Buffer = Buffer.from(response.data);
      let contentType =
        response.headers['content-type'] || 'application/octet-stream';
      let contentLength = fileData.length;

      this.logger.log(`[proxy-model] Content-Type: ${contentType}`);

      // 如果是ZIP文件，解压并提取3D模型文件
      if (
        decodedUrl.toLowerCase().includes('.zip') ||
        contentType.includes('zip') ||
        contentType.includes('application/zip')
      ) {
        this.logger.log(`[proxy-model] 检测到ZIP文件，开始解压...`);
        try {
          const zip = new AdmZip(fileData);
          const zipEntries = zip.getEntries();

          this.logger.log(
            `[proxy-model] ZIP解压成功，包含 ${zipEntries.length} 个文件`,
          );

          // 列出所有文件便于调试
          const allFiles = zipEntries.map((e) => e.entryName);
          this.logger.log(`[proxy-model] ZIP文件列表: ${allFiles.join(', ')}`);

          // 按优先级查找3D模型文件: GLB > GLTF > OBJ
          let modelEntry = zipEntries.find((entry) =>
            entry.entryName.toLowerCase().endsWith('.glb'),
          );

          if (!modelEntry) {
            modelEntry = zipEntries.find((entry) =>
              entry.entryName.toLowerCase().endsWith('.gltf'),
            );
          }

          if (!modelEntry) {
            modelEntry = zipEntries.find((entry) =>
              entry.entryName.toLowerCase().endsWith('.obj'),
            );
          }

          if (modelEntry) {
            this.logger.log(
              `[proxy-model] 找到模型文件: ${modelEntry.entryName}`,
            );
            fileData = modelEntry.getData();
            const entryName = modelEntry.entryName.toLowerCase();
            let modelType = 'glb'; // 默认类型
            if (entryName.endsWith('.glb')) {
              contentType = 'model/gltf-binary';
              modelType = 'glb';
            } else if (entryName.endsWith('.gltf')) {
              contentType = 'model/gltf+json';
              modelType = 'gltf';
            } else if (entryName.endsWith('.obj')) {
              contentType = 'text/plain'; // OBJ 是文本格式
              modelType = 'obj';
            }
            contentLength = fileData.length;
            this.logger.log(
              `[proxy-model] 模型类型: ${modelType}, 大小: ${contentLength} bytes`,
            );
            // 添加自定义头部，告知前端实际的模型类型
            res.setHeader('X-Model-Type', modelType);
          } else {
            // 列出ZIP中的所有文件，便于调试
            const fileList = zipEntries.map((e) => e.entryName).join(', ');
            this.logger.error(
              `[proxy-model] ZIP中未找到3D模型文件。ZIP内容: ${fileList}`,
            );
            throw new HttpException(
              `ZIP文件中未找到3D模型文件（GLB/GLTF/OBJ）。ZIP内容: ${fileList}`,
              HttpStatus.BAD_REQUEST,
            );
          }
        } catch (zipError: any) {
          this.logger.error(
            `[proxy-model] ZIP处理失败: ${zipError.message}`,
            zipError.stack,
          );
          if (zipError instanceof HttpException) {
            throw zipError;
          }
          throw new HttpException(
            `ZIP解压失败: ${zipError.message}`,
            HttpStatus.INTERNAL_SERVER_ERROR,
          );
        }
      }

      // 设置响应头
      res.setHeader('Content-Type', contentType);
      res.setHeader('Content-Length', contentLength);
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
      res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
      res.setHeader('Cache-Control', 'public, max-age=3600'); // 缓存1小时

      // 发送文件数据
      this.logger.log(`[proxy-model] 发送响应，大小: ${contentLength} bytes`);
      res.send(fileData);
    } catch (error: any) {
      this.logger.error(
        `[proxy-model] 请求处理失败: ${error.message}`,
        error.stack,
      );

      if (error instanceof HttpException) {
        throw error;
      }
      if (error.response) {
        res.status(error.response.status).json({
          message: `代理请求失败: ${error.response.statusText}`,
          status: error.response.status,
        });
      } else if (error.code === 'ECONNABORTED') {
        res.status(HttpStatus.REQUEST_TIMEOUT).json({
          message: '请求超时，请稍后重试',
        });
      } else if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
        res.status(HttpStatus.BAD_GATEWAY).json({
          message: `无法连接到目标服务器: ${error.message}`,
        });
      } else {
        res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
          message: `代理请求失败: ${error.message}`,
          error:
            process.env.NODE_ENV === 'development' ? error.stack : undefined,
        });
      }
    }
  }

  /**
   * 代理预览图（解决CORS问题）
   * GET /api/ai-3d/proxy-preview
   */
  @Get('proxy-preview')
  @Public() // 允许公开访问，因为预览图URL已经包含签名
  async proxyPreview(@Query('url') url: string, @Res() res: Response) {
    if (!url) {
      throw new HttpException('URL参数不能为空', HttpStatus.BAD_REQUEST);
    }

    try {
      // URL解码（处理URL编码）
      let decodedUrl: string;
      try {
        decodedUrl = decodeURIComponent(url);
      } catch (e) {
        // 如果解码失败，使用原始URL
        decodedUrl = url;
      }

      // 验证URL是否为腾讯云COS链接（安全验证）
      if (
        !decodedUrl.includes('tencentcos.cn') &&
        !decodedUrl.includes('qcloud.com')
      ) {
        throw new HttpException(
          '不支持的URL来源，仅支持腾讯云COS链接',
          HttpStatus.BAD_REQUEST,
        );
      }

      // 验证URL格式
      try {
        new URL(decodedUrl);
      } catch (e) {
        throw new HttpException('URL格式无效', HttpStatus.BAD_REQUEST);
      }

      // 从源URL获取图片
      const response = await axios.get(decodedUrl, {
        responseType: 'arraybuffer',
        timeout: 30000, // 30秒超时
        maxContentLength: 10 * 1024 * 1024, // 最大10MB
        headers: {
          'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
          Accept: 'image/*',
        },
      });

      const imageData = Buffer.from(response.data);
      const contentType = response.headers['content-type'] || 'image/jpeg';
      const contentLength = imageData.length;

      // 设置响应头
      res.setHeader('Content-Type', contentType);
      res.setHeader('Content-Length', contentLength);
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
      res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
      res.setHeader('Cache-Control', 'public, max-age=86400'); // 缓存24小时

      // 发送图片数据
      res.send(imageData);
    } catch (error: any) {
      if (error instanceof HttpException) {
        throw error;
      }
      if (error.response) {
        res.status(error.response.status).json({
          message: `代理请求失败: ${error.response.statusText}`,
          status: error.response.status,
        });
      } else if (error.code === 'ECONNABORTED') {
        res.status(HttpStatus.REQUEST_TIMEOUT).json({
          message: '请求超时，请稍后重试',
        });
      } else if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
        res.status(HttpStatus.BAD_GATEWAY).json({
          message: `无法连接到目标服务器: ${error.message}`,
        });
      } else {
        res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
          message: `代理请求失败: ${error.message}`,
          error:
            process.env.NODE_ENV === 'development' ? error.stack : undefined,
        });
      }
    }
  }
}
