// ============================================================
// DOCUMENTS ROUTES — S3-backed document upload & management
// ============================================================

import express = require('express');
import type { Request, Response } from 'express';
import multer = require('multer');
import crypto = require('crypto');
const db = require('../db/database');
const { authMiddleware } = require('../middleware/auth');
const logger = require('../utils/logger');

const router = express.Router();
router.use(authMiddleware);

const upload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 10 * 1024 * 1024 },
});

const ALLOWED_TYPES: string[] = [
  'application/pdf',
  'image/jpeg', 'image/png', 'image/gif',
  'application/msword',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  'text/plain', 'text/csv',
];

let _s3Client: any = null;
function getS3Client(): any {
  if (_s3Client) return _s3Client;
  try {
    const { S3Client } = require('@aws-sdk/client-s3');
    const region = process.env.S3_REGION || process.env.AWS_BEDROCK_REGION || 'us-east-1';
    const config: any = { region };

    if (process.env.S3_ENDPOINT) {
      config.endpoint = process.env.S3_ENDPOINT;
      config.forcePathStyle = process.env.S3_FORCE_PATH_STYLE === 'true';
    }

    const accessKey = process.env.S3_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY_ID;
    const secretKey = process.env.S3_SECRET_ACCESS_KEY || process.env.AWS_SECRET_ACCESS_KEY;
    if (accessKey && secretKey) {
      config.credentials = { accessKeyId: accessKey, secretAccessKey: secretKey };
    }

    _s3Client = new S3Client(config);
    return _s3Client;
  } catch (e) {
    return null;
  }
}

function isS3Configured(): boolean {
  return !!process.env.S3_BUCKET && !!getS3Client();
}

router.get('/documents', async function (req: Request, res: Response) {
  try {
    if (!isS3Configured()) return res.json({ success: true, documents: [], s3_configured: false });
    const rows = await db.all(
      'SELECT id, filename, mime_type, size_bytes, description, created_at FROM user_documents WHERE user_id = $1 ORDER BY created_at DESC',
      [req.user!.id]
    );
    res.json({ success: true, documents: rows, s3_configured: true });
  } catch (e: any) { logger.error('GET /documents', e.message); res.status(500).json({ error: 'Could not list documents' }); }
});

router.post('/documents/upload', upload.single('file'), async function (req: Request, res: Response) {
  try {
    if (!isS3Configured()) return res.status(400).json({ error: 'S3 not configured. Set S3_BUCKET and S3_REGION in .env' });
    if (!req.file) return res.status(400).json({ error: 'No file uploaded' });
    if (!ALLOWED_TYPES.includes(req.file.mimetype)) {
      return res.status(400).json({ error: 'File type not allowed. Supported: PDF, images, Word docs, text, CSV' });
    }
    const fileType = require('../utils/fileType');
    if (!fileType.matches(req.file.mimetype, req.file.buffer)) {
      return res.status(400).json({ error: 'File contents do not match the declared type.' });
    }

    const { PutObjectCommand } = require('@aws-sdk/client-s3');
    const prefix = process.env.S3_PREFIX || 'documents/';
    const uuid = crypto.randomUUID();
    const s3Key = prefix + req.user!.id + '/' + uuid + '/' + req.file.originalname;

    await getS3Client().send(new PutObjectCommand({
      Bucket: process.env.S3_BUCKET,
      Key: s3Key,
      Body: req.file.buffer,
      ContentType: req.file.mimetype,
      ServerSideEncryption: 'AES256',
    }));

    const result = await db.run(
      'INSERT INTO user_documents (user_id, s3_key, filename, mime_type, size_bytes, description) VALUES ($1,$2,$3,$4,$5,$6)',
      [req.user!.id, s3Key, req.file.originalname, req.file.mimetype, req.file.size, req.body.description || '']
    );

    res.json({ success: true, id: result.lastInsertRowid, filename: req.file.originalname });
    logger.audit(req.user!.id, 'document_upload', 'Uploaded: ' + (req.file ? req.file.originalname : 'unknown'), req, { category: 'documents' });
  } catch (e: any) { logger.error('POST /documents/upload', e.message); res.status(500).json({ error: 'Upload failed' }); }
});

router.get('/documents/:id/download', async function (req: Request, res: Response) {
  try {
    if (!isS3Configured()) return res.status(400).json({ error: 'S3 not configured' });
    const doc = await db.get(
      'SELECT * FROM user_documents WHERE id = $1 AND user_id = $2',
      [req.params.id, req.user!.id]
    );
    if (!doc) return res.status(404).json({ error: 'Document not found' });

    const { GetObjectCommand } = require('@aws-sdk/client-s3');
    const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');

    const command = new GetObjectCommand({
      Bucket: process.env.S3_BUCKET,
      Key: doc.s3_key,
      ResponseContentDisposition: 'attachment; filename="' + doc.filename + '"',
    });
    const url = await getSignedUrl(getS3Client(), command, { expiresIn: 300 });

    res.json({ success: true, url });
    logger.audit(req.user!.id, 'document_download', 'Downloaded document ' + req.params.id, req, { category: 'documents' });
  } catch (e: any) { logger.error('GET /documents/:id/download', e.message); res.status(500).json({ error: 'Download failed' }); }
});

router.delete('/documents/:id', async function (req: Request, res: Response) {
  try {
    if (!isS3Configured()) return res.status(400).json({ error: 'S3 not configured' });
    const doc = await db.get(
      'SELECT * FROM user_documents WHERE id = $1 AND user_id = $2',
      [req.params.id, req.user!.id]
    );
    if (!doc) return res.status(404).json({ error: 'Document not found' });

    try {
      const { DeleteObjectCommand } = require('@aws-sdk/client-s3');
      await getS3Client().send(new DeleteObjectCommand({ Bucket: process.env.S3_BUCKET, Key: doc.s3_key }));
    } catch (s3err: any) {
      logger.warn('S3 delete failed (continuing with DB delete):', s3err.message);
    }

    await db.run('DELETE FROM user_documents WHERE id = $1 AND user_id = $2', [req.params.id, req.user!.id]);
    res.json({ success: true });
    logger.audit(req.user!.id, 'document_delete', 'Deleted document ' + req.params.id, req, { category: 'documents' });
  } catch (e: any) { logger.error('DELETE /documents/:id', e.message); res.status(500).json({ error: 'Delete failed' }); }
});

export = router;
