/**
 * @ai-summary Controller for user data import endpoints
 * @ai-context Handles multipart uploads, validation, and import orchestration
 */

import { FastifyRequest, FastifyReply } from 'fastify';
import * as fsp from 'fs/promises';
import * as path from 'path';
import FileType from 'file-type';
import { logger } from '../../../core/logging/logger';
import { pool } from '../../../core/config/database';
import { UserImportService } from '../domain/user-import.service';
import { importRequestSchema } from './user-import.validation';

export class UserImportController {
  private readonly importService: UserImportService;

  constructor() {
    this.importService = new UserImportService(pool);
  }

  /**
   * POST /api/user/import
   * Uploads and imports user data archive
   */
  async uploadAndImport(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    const userId = request.user?.sub;
    if (!userId) {
      return reply.code(401).send({ error: 'Unauthorized' });
    }

    logger.info('Processing user data import request', { userId });

    let tempFilePath: string | null = null;

    try {
      // Get multipart file
      const data = await request.file();

      if (!data) {
        return reply.code(400).send({
          error: 'Bad Request',
          message: 'No file uploaded',
        });
      }

      // Validate Content-Type header
      const contentType = data.mimetype;
      const allowedTypes = ['application/gzip', 'application/x-gzip', 'application/x-tar'];

      if (!allowedTypes.includes(contentType)) {
        logger.warn('Invalid Content-Type for import upload', {
          userId,
          contentType,
          fileName: data.filename,
        });
        return reply.code(415).send({
          error: 'Unsupported Media Type',
          message: 'Only tar.gz archives are allowed (application/gzip)',
        });
      }

      // Read file to buffer for magic byte validation
      const chunks: Buffer[] = [];
      for await (const chunk of data.file) {
        chunks.push(chunk);
      }
      const fileBuffer = Buffer.concat(chunks);

      // Validate actual file content using magic bytes
      const detectedType = await FileType.fromBuffer(fileBuffer);

      if (!detectedType || detectedType.mime !== 'application/gzip') {
        logger.warn('File content does not match gzip format', {
          userId,
          detectedType: detectedType?.mime,
          fileName: data.filename,
        });
        return reply.code(415).send({
          error: 'Unsupported Media Type',
          message: 'File content is not a valid gzip archive',
        });
      }

      // Save to temp file for processing
      const timestamp = Date.now();
      tempFilePath = path.join('/tmp', `import-upload-${userId}-${timestamp}.tar.gz`);
      await fsp.writeFile(tempFilePath, fileBuffer);

      logger.info('Import archive uploaded and validated', { userId, tempFilePath });

      // Parse request body for mode (if provided)
      const fields: Record<string, any> = {};
      if (data.fields) {
        for (const [key, value] of Object.entries(data.fields)) {
          fields[key] = (value as any).value;
        }
      }

      const validatedFields = importRequestSchema.parse(fields);
      const mode = validatedFields.mode || 'merge';

      // Execute import based on mode
      let result;
      if (mode === 'replace') {
        result = await this.importService.executeReplace(userId, tempFilePath);
      } else {
        result = await this.importService.executeMerge(userId, tempFilePath);
      }

      logger.info('Import completed', { userId, mode, result });

      return reply.code(200).send(result);
    } catch (error) {
      logger.error('Import failed', {
        userId,
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
      });

      return reply.code(500).send({
        error: 'Internal Server Error',
        message: error instanceof Error ? error.message : 'Import failed',
      });
    } finally {
      // Cleanup temp upload file
      if (tempFilePath) {
        try {
          await fsp.unlink(tempFilePath);
        } catch {
          // Cleanup failed, but continue
        }
      }
    }
  }

  /**
   * POST /api/user/import/preview
   * Generates preview of import data without executing import
   */
  async generatePreview(request: FastifyRequest, reply: FastifyReply): Promise<void> {
    const userId = request.user?.sub;
    if (!userId) {
      return reply.code(401).send({ error: 'Unauthorized' });
    }

    logger.info('Generating import preview', { userId });

    let tempFilePath: string | null = null;

    try {
      // Get multipart file
      const data = await request.file();

      if (!data) {
        return reply.code(400).send({
          error: 'Bad Request',
          message: 'No file uploaded',
        });
      }

      // Validate Content-Type header
      const contentType = data.mimetype;
      const allowedTypes = ['application/gzip', 'application/x-gzip', 'application/x-tar'];

      if (!allowedTypes.includes(contentType)) {
        logger.warn('Invalid Content-Type for preview upload', {
          userId,
          contentType,
          fileName: data.filename,
        });
        return reply.code(415).send({
          error: 'Unsupported Media Type',
          message: 'Only tar.gz archives are allowed (application/gzip)',
        });
      }

      // Read file to buffer for magic byte validation
      const chunks: Buffer[] = [];
      for await (const chunk of data.file) {
        chunks.push(chunk);
      }
      const fileBuffer = Buffer.concat(chunks);

      // Validate actual file content using magic bytes
      const detectedType = await FileType.fromBuffer(fileBuffer);

      if (!detectedType || detectedType.mime !== 'application/gzip') {
        logger.warn('File content does not match gzip format', {
          userId,
          detectedType: detectedType?.mime,
          fileName: data.filename,
        });
        return reply.code(415).send({
          error: 'Unsupported Media Type',
          message: 'File content is not a valid gzip archive',
        });
      }

      // Save to temp file for processing
      const timestamp = Date.now();
      tempFilePath = path.join('/tmp', `import-preview-${userId}-${timestamp}.tar.gz`);
      await fsp.writeFile(tempFilePath, fileBuffer);

      logger.info('Preview archive uploaded and validated', { userId, tempFilePath });

      // Generate preview
      const preview = await this.importService.generatePreview(userId, tempFilePath);

      logger.info('Preview generated', { userId, preview });

      return reply.code(200).send(preview);
    } catch (error) {
      logger.error('Preview generation failed', {
        userId,
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
      });

      return reply.code(500).send({
        error: 'Internal Server Error',
        message: error instanceof Error ? error.message : 'Preview generation failed',
      });
    } finally {
      // Cleanup temp upload file
      if (tempFilePath) {
        try {
          await fsp.unlink(tempFilePath);
        } catch {
          // Cleanup failed, but continue
        }
      }
    }
  }
}
