/**
 * Knowledge Base Documents API
 * GET - List documents
 * POST - Upload new document
 */

import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { getAuthenticatedUser } from "@/lib/utils/auth-helpers.util";
import { KnowledgeBaseService } from "@/lib/services/knowledge-base.service";
import { validateCSRFToken } from "@/lib/csrf";
import { rateLimiters, applyRateLimit } from "@/lib/rate-limiter";
import { logger } from "@/lib/logger";
import { createId } from "@paralleldrive/cuid2";
import { uploadToConvexStorage, getConvexFileUrl } from "@/lib/convex-storage";
import {
  ALLOWED_MEDIA_TYPES,
  MAX_MEDIA_SIZE,
  getMediaType,
} from "@/lib/types/knowledge-base.types";
import { PineconeMultimodalService } from "@/lib/services/pinecone-multimodal.service";

const scopedLogger = logger.scope("KnowledgeBaseDocumentsAPI");

/**
 * GET /api/dashboard/knowledge-base/documents
 * List all documents for the user
 */
export async function GET(request: NextRequest) {
  try {
    const user = await getAuthenticatedUser(request, auth);

    if (!user) {
      return NextResponse.json(
        { success: false, error: "Unauthorized" },
        { status: 401 },
      );
    }

    const url = new URL(request.url);
    const category = url.searchParams.get("category") || undefined;
    const status = (url.searchParams.get("status") as any) || undefined;
    const limit = parseInt(url.searchParams.get("limit") || "50", 10);
    const offset = parseInt(url.searchParams.get("offset") || "0", 10);

    const { documents, total } = await KnowledgeBaseService.getDocuments(
      user.userId,
      {
        category,
        status,
        limit,
        offset,
      },
    );

    return NextResponse.json({
      success: true,
      documents,
      total,
      limit,
      offset,
    });
  } catch (error) {
    scopedLogger.error("Failed to get documents", error);
    return NextResponse.json(
      { success: false, error: "Internal server error" },
      { status: 500 },
    );
  }
}

/**
 * POST /api/dashboard/knowledge-base/documents
 * Upload a new document
 */
export async function POST(request: NextRequest) {
  try {
    // Rate limiting
    const rateLimitResponse = await applyRateLimit(
      request,
      rateLimiters.authGeneral,
    );
    if (rateLimitResponse) {
      return rateLimitResponse;
    }

    const user = await getAuthenticatedUser(request, auth);

    if (!user) {
      return NextResponse.json(
        { success: false, error: "Unauthorized" },
        { status: 401 },
      );
    }

    // CSRF protection
    if (!validateCSRFToken(request)) {
      return NextResponse.json(
        { success: false, error: "Invalid CSRF token" },
        { status: 403 },
      );
    }

    // Parse multipart form data
    const formData = await request.formData();
    const file = formData.get("file") as File | null;
    const title = (formData.get("title") as string) || undefined;
    const description = (formData.get("description") as string) || undefined;
    const category = (formData.get("category") as string) || "general";

    if (!file) {
      return NextResponse.json(
        { success: false, error: "No file provided" },
        { status: 400 },
      );
    }

    // Validate file type (multimodal: documents, images, videos, audio)
    const allowedTypes = ALLOWED_MEDIA_TYPES as readonly string[];
    if (!allowedTypes.includes(file.type)) {
      return NextResponse.json(
        {
          success: false,
          error: `Invalid file type. Allowed types: PDF, Word, Text, Markdown, CSV, PNG, JPEG, WebP, MP4, MOV, MP3, WAV, M4A`,
        },
        { status: 400 },
      );
    }

    // Validate file size (50MB for multimodal content)
    if (file.size > MAX_MEDIA_SIZE) {
      return NextResponse.json(
        {
          success: false,
          error: `File size exceeds maximum of ${MAX_MEDIA_SIZE / (1024 * 1024)}MB`,
        },
        { status: 400 },
      );
    }

    // Generate unique filename
    const fileExtension = file.name.split(".").pop() || "";
    const filename = `${createId()}.${fileExtension}`;
    const storagePath = `knowledge-base/${user.userId}/${filename}`;

    // Get file buffer
    const arrayBuffer = await file.arrayBuffer();
    const buffer = Buffer.from(arrayBuffer);

    // Upload file to Convex storage (cloud-ready, works on DO/AWS)
    let mediaUrl: string | null = null;
    let storageId: string | null = null;
    try {
      const uploadResult = await uploadToConvexStorage({
        buffer: buffer,
        fileName: filename,
        fileType: file.type,
        fileSize: file.size,
        bucket: "knowledge-base",
        entityId: undefined, // will be set after document creation
        entityType: "knowledge-base-document",
        uploadedBy: user.userId,
      });
      storageId = uploadResult.storageId;

      // Get the serving URL
      mediaUrl = await getConvexFileUrl(storageId);
    } catch (storageError) {
      scopedLogger.error("Convex storage upload failed", storageError);
      // Continue without mediaUrl - embedding can still work
    }

    // Determine media type from MIME
    const mediaType = getMediaType(file.type);

    // Create document record
    const document = await KnowledgeBaseService.createDocument(user.userId, {
      filename,
      originalName: file.name,
      mimeType: file.type,
      fileSize: file.size,
      storagePath,
      title,
      description,
      category,
    });

    // Determine content for embedding: extract text for documents, buffer for media
    let embeddingContent: string | Buffer = buffer;
    if (mediaType === "document") {
      if (
        file.type === "text/plain" ||
        file.type === "text/markdown" ||
        file.type === "text/csv"
      ) {
        embeddingContent = buffer.toString("utf-8");
      } else if (file.type === "application/pdf") {
        // Extract actual text from PDF using pdf-parse
        try {
          // eslint-disable-next-line @typescript-eslint/no-require-imports
          const pdfParse = require("pdf-parse") as (buf: Buffer) => Promise<{ text: string; numpages: number }>;
          const pdfData = await pdfParse(buffer);
          if (pdfData.text && pdfData.text.trim().length > 0) {
            embeddingContent = pdfData.text;
            scopedLogger.info("PDF text extracted", {
              documentId: document.id,
              textLength: pdfData.text.length,
              pages: pdfData.numpages,
            });
          }
          // If no text extracted (scanned PDF), fall through to buffer
        } catch (pdfError) {
          scopedLogger.warn("PDF text extraction failed, using buffer", {
            documentId: document.id,
            error: pdfError instanceof Error ? pdfError.message : String(pdfError),
          });
        }
      }
      // For Word docs without text extraction, pass buffer for AI description
    }

    // Generate embedding and upsert to Pinecone
    let embeddingId: string | undefined;
    let aiDescription: string | undefined;

    if (PineconeMultimodalService.isConfigured()) {
      try {
        const vectorId = `doc-${document.id}`;
        const result = await PineconeMultimodalService.embedAndUpsert(
          user.userId,
          vectorId,
          embeddingContent,
          file.type,
          {
            title: title || file.name,
            category: category || "general",
            mediaType,
            documentId: document.id,
          },
        );

        embeddingId = result.embeddingId;
        aiDescription = result.aiDescription;

        scopedLogger.info("Embedding generated", {
          documentId: document.id,
          embeddingId,
          hasAiDescription: !!aiDescription,
        });
      } catch (embedError) {
        // Log but don't fail the upload — embedding can be retried
        scopedLogger.error("Embedding failed, upload still saved", embedError, {
          documentId: document.id,
        });
      }
    } else {
      scopedLogger.warn("Pinecone not configured, skipping embedding", {
        documentId: document.id,
      });
    }

    // Update document status to COMPLETED
    try {
      await KnowledgeBaseService.updateDocumentStatus(
        document.id,
        "COMPLETED",
        {
          embeddingModel: embeddingId
            ? "gemini-embedding-2-preview"
            : undefined,
        },
      );
    } catch (updateError) {
      scopedLogger.warn("Failed to update document status", {
        documentId: document.id,
        error: updateError,
      });
    }

    scopedLogger.info("Document uploaded", {
      userId: user.userId,
      documentId: document.id,
      filename: file.name,
      mediaType,
      mediaUrl,
    });

    return NextResponse.json(
      {
        success: true,
        document: {
          ...document,
          mediaType,
          mediaUrl,
          storageId,
          embeddingId,
          aiDescription,
        },
        message: "Document uploaded successfully.",
      },
      { status: 201 },
    );
  } catch (error) {
    scopedLogger.error("Failed to upload document", error);
    return NextResponse.json(
      { success: false, error: "Failed to upload document" },
      { status: 500 },
    );
  }
}
