import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import fastifyMultipart from '@fastify/multipart';
import {
  voiceEnrollmentService,
  analysisService,
  batchAnalysisService,
  voicePrintEnv,
} from '../services/voiceprint';

interface AuthenticatedRequest extends FastifyRequest {
  user?: { id: string; email: string; role: string };
  authType?: 'jwt' | 'api-key' | 'anonymous';
}

export async function voiceprintRoutes(fastify: FastifyInstance) {
  // P1-2 fix: Require authentication on all VoicePrint routes
  fastify.addHook('onRequest', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as AuthenticatedRequest;
    if (authReq.authType === 'anonymous' || !authReq.user?.id || authReq.user.id === 'anonymous') {
      return reply.code(401).send({ error: 'Authentication required' });
    }
  });

  // P1-3 fix: Register multipart for audio file uploads
  await fastify.register(fastifyMultipart, {
    limits: {
      fileSize: voicePrintEnv.ENROLLMENT_MAX_DURATION_SEC > 0
        ? 50 * 1024 * 1024 // 50MB max file size for audio
        : 50 * 1024 * 1024,
    },
  });
  // Enroll a new voice profile
  fastify.post('/enroll', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as AuthenticatedRequest;
    const userId = authReq.user?.id;

    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    // P1-3 fix: Parse multipart form-data for audio upload
    let name: string | undefined;
    let audioBuffer: Buffer | undefined;

    for await (const part of request.files()) {
      if (part.type === 'file') {
        audioBuffer = await part.toBuffer();
        name = name || part.filename || 'voice_enrollment';
      } else if (part.fieldname === 'name') {
        name = part.value;
      }
    }

    if (!audioBuffer || audioBuffer.length === 0) {
      return reply.code(400).send({ error: 'audio file is required' });
    }

    try {
      const enrollment = await voiceEnrollmentService.enroll(
        userId,
        name || 'voice_enrollment',
        audioBuffer
      );
      return reply.code(201).send({
        enrollment: {
          id: enrollment.id,
          name: enrollment.name,
          isActive: enrollment.isActive,
          createdAt: enrollment.createdAt,
        },
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Enrollment failed';
      return reply.code(422).send({ error: message });
    }
  });

  // List user's voice enrollments
  fastify.get('/enrollments', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as AuthenticatedRequest;
    const userId = authReq.user?.id;

    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    const isActive = request.query as { isActive?: string };
    const limit = request.query as { limit?: string };
    const offset = request.query as { offset?: string };

    const enrollments = await voiceEnrollmentService.listEnrollments(userId, {
      isActive: isActive.isActive !== undefined
        ? isActive.isActive === 'true'
        : undefined,
      limit: limit.limit ? parseInt(limit.limit, 10) : undefined,
      offset: offset.offset ? parseInt(offset.offset, 10) : undefined,
    });

    return reply.send({
      enrollments: enrollments.map((e) => ({
        id: e.id,
        name: e.name,
        isActive: e.isActive,
        createdAt: e.createdAt,
      })),
    });
  });

  // Remove an enrollment
  fastify.delete('/enrollments/:id', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as AuthenticatedRequest;
    const userId = authReq.user?.id;

    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    const enrollmentId = (request.params as { id: string }).id;

    try {
      const enrollment = await voiceEnrollmentService.removeEnrollment(
        enrollmentId,
        userId
      );
      return reply.send({
        enrollment: {
          id: enrollment.id,
          name: enrollment.name,
          isActive: enrollment.isActive,
        },
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Removal failed';
      return reply.code(404).send({ error: message });
    }
  });

  // Analyze a single audio file
  fastify.post('/analyze', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as AuthenticatedRequest;
    const userId = authReq.user?.id;

    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    // P1-3 fix: Parse multipart form-data for audio upload
    let audioBuffer: Buffer | undefined;
    let enrollmentId: string | undefined;
    let audioUrl: string | undefined;

    for await (const part of request.files()) {
      if (part.type === 'file') {
        audioBuffer = await part.toBuffer();
      } else if (part.fieldname === 'enrollmentId') {
        enrollmentId = part.value;
      } else if (part.fieldname === 'audioUrl') {
        audioUrl = part.value;
      }
    }

    if (!audioBuffer || audioBuffer.length === 0) {
      return reply.code(400).send({ error: 'audio file is required' });
    }

    try {
      const result = await analysisService.analyze(userId, audioBuffer, {
        enrollmentId,
        audioUrl,
      });
      return reply.code(201).send({
        analysis: {
          id: result.id,
          isSynthetic: result.isSynthetic,
          confidence: result.confidence,
          analysisResult: result.analysisResult,
          createdAt: result.createdAt,
        },
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Analysis failed';
      return reply.code(422).send({ error: message });
    }
  });

  // Get analysis result by ID
  fastify.get('/results/:id', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as AuthenticatedRequest;
    const userId = authReq.user?.id;

    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    const analysisId = (request.params as { id: string }).id;
    const result = await analysisService.getResult(analysisId, userId);

    if (!result) {
      return reply.code(404).send({ error: 'Analysis not found' });
    }

    return reply.send({
      analysis: {
        id: result.id,
        isSynthetic: result.isSynthetic,
        confidence: result.confidence,
        analysisResult: result.analysisResult,
        createdAt: result.createdAt,
      },
    });
  });

  // Get analysis history
  fastify.get('/history', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as AuthenticatedRequest;
    const userId = authReq.user?.id;

    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    const query = request.query as {
      limit?: string;
      offset?: string;
      isSynthetic?: string;
    };

    const results = await analysisService.getHistory(userId, {
      limit: query.limit ? parseInt(query.limit, 10) : undefined,
      offset: query.offset ? parseInt(query.offset, 10) : undefined,
      isSynthetic: query.isSynthetic !== undefined
        ? query.isSynthetic === 'true'
        : undefined,
    });

    return reply.send({
      analyses: results.map((r) => ({
        id: r.id,
        isSynthetic: r.isSynthetic,
        confidence: r.confidence,
        createdAt: r.createdAt,
      })),
    });
  });

  // Batch analyze multiple audio files
  fastify.post('/batch', async (request: FastifyRequest, reply: FastifyReply) => {
    const authReq = request as AuthenticatedRequest;
    const userId = authReq.user?.id;

    if (!userId) {
      return reply.code(401).send({ error: 'User ID required' });
    }

    // P1-3 fix: Parse multipart form-data for multiple audio uploads
    const files: Array<{ name: string; buffer: Buffer; audioUrl?: string }> = [];
    let enrollmentId: string | undefined;

    for await (const part of request.files()) {
      if (part.type === 'file') {
        const buffer = await part.toBuffer();
        files.push({
          name: part.filename || `file_${files.length}`,
          buffer,
        });
      } else if (part.fieldname === 'enrollmentId') {
        enrollmentId = part.value;
      } else if (part.fieldname === 'audioUrl') {
        if (files.length > 0) {
          files[files.length - 1].audioUrl = part.value;
        }
      }
    }

    if (files.length === 0) {
      return reply.code(400).send({ error: 'at least one audio file is required' });
    }

    try {
      const result = await batchAnalysisService.analyzeBatch(
        userId,
        files,
        { enrollmentId }
      );

      return reply.code(201).send({
        jobId: result.jobId,
        results: result.results.map((r) => ({
          id: r.id,
          isSynthetic: r.isSynthetic,
          confidence: r.confidence,
        })),
        summary: result.summary,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Batch analysis failed';
      return reply.code(422).send({ error: message });
    }
  });
}
