import { Router } from 'express';
import multer from 'multer';
import { randomUUID } from 'crypto';
import { uploadBuffer, deleteObject, publicUrl } from '../lib/minio.js';

const router = Router();

// 500 MB limit — video files can be large
const upload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 500 * 1024 * 1024 },
});

function assetType(mimetype) {
  if (mimetype.startsWith('image/')) return 'image';
  if (mimetype.startsWith('video/')) return 'video';
  if (mimetype.startsWith('audio/')) return 'audio';
  return 'other';
}

function makeObjectKey(originalName, type) {
  const ext = originalName.split('.').pop().toLowerCase();
  const safe = originalName
    .replace(/\.[^.]+$/, '')       // strip extension
    .replace(/[^a-zA-Z0-9_-]/g, '_')
    .slice(0, 40);
  return `assets/${type}/${Date.now()}-${randomUUID().slice(0, 8)}-${safe}.${ext}`;
}

// ── GET /api/assets ──────────────────────────────────────────────────────────
// ?type=image|video|audio|other   optional filter
// ?q=searchterm                   optional filename search
router.get('/', async (req, res) => {
  const pool = req.app.get('pool');
  const { type, q } = req.query;
  try {
    let query = `
      SELECT id, asset_key, asset_type, original_filename, filename,
             minio_object_key, mime_type, width, height,
             duration_seconds, file_size_bytes, description,
             license, copyright_holder, source_url, uploader,
             created_at
      FROM shared_assets
      WHERE 1=1
    `;
    const params = [];
    if (type) {
      params.push(type);
      query += ` AND asset_type = $${params.length}`;
    }
    if (q) {
      params.push(`%${q}%`);
      query += ` AND (original_filename ILIKE $${params.length}
                   OR description      ILIKE $${params.length}
                   OR copyright_holder ILIKE $${params.length}
                   OR source_url       ILIKE $${params.length})`;
    }
    query += ' ORDER BY created_at DESC';

    const result = await pool.query(query, params);

    // Attach public URL to each row
    const assets = result.rows.map(row => ({
      ...row,
      url: row.minio_object_key ? publicUrl(row.minio_object_key) : null,
    }));

    res.json({ assets });
  } catch (err) {
    console.error('List assets error:', err);
    res.status(500).json({ error: 'Failed to list assets' });
  }
});

// ── POST /api/assets/upload ──────────────────────────────────────────────────
// Multipart form fields:
//   file      — the file
//   width     — integer (from client-side inspection)
//   height    — integer
//   duration  — float (seconds)
//   description — optional string
router.post('/upload', upload.single('file'), async (req, res) => {
  const pool = req.app.get('pool');
  if (!req.file) return res.status(400).json({ error: 'No file provided' });

  const { originalname, mimetype, buffer, size } = req.file;
  const width            = req.body.width      ? parseInt(req.body.width, 10)  : null;
  const height           = req.body.height     ? parseInt(req.body.height, 10) : null;
  const duration         = req.body.duration   ? parseFloat(req.body.duration) : null;
  const description      = req.body.description      || null;
  const license          = req.body.license          || null;
  const copyright_holder = req.body.copyright_holder || null;
  const source_url       = req.body.source_url       || null;
  const uploader         = req.body.uploader         || null;

  const type       = assetType(mimetype);
  const objectKey  = makeObjectKey(originalname, type);

  try {
    const url = await uploadBuffer(objectKey, buffer, mimetype);

    const result = await pool.query(
      `INSERT INTO shared_assets (
        asset_key, asset_type, filename, original_filename,
        minio_object_key, mime_type,
        width, height, duration_seconds, file_size_bytes,
        description, has_audio,
        license, copyright_holder, source_url, uploader,
        updated_at
      ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,NOW())
      RETURNING *`,
      [
        objectKey,
        type,
        originalname,
        originalname,
        objectKey,
        mimetype,
        width,
        height,
        duration,
        size,
        description,
        type === 'video' || type === 'audio',
        license,
        copyright_holder,
        source_url,
        uploader,
      ]
    );

    res.status(201).json({
      asset: { ...result.rows[0], url },
    });
  } catch (err) {
    console.error('Upload error:', err);
    res.status(500).json({ error: 'Upload failed', detail: err.message });
  }
});

// ── GET /api/assets/:id ──────────────────────────────────────────────────────
router.get('/:id', async (req, res) => {
  const pool = req.app.get('pool');
  try {
    const result = await pool.query('SELECT * FROM shared_assets WHERE id = $1', [req.params.id]);
    if (!result.rows.length) return res.status(404).json({ error: 'Not found' });
    const row = result.rows[0];
    res.json({ asset: { ...row, url: row.minio_object_key ? publicUrl(row.minio_object_key) : null } });
  } catch (err) {
    res.status(500).json({ error: 'Failed to fetch asset' });
  }
});

// ── PATCH /api/assets/:id ────────────────────────────────────────────────────
// Accepts any subset of: description, license, copyright_holder, source_url, uploader
// Pass empty string to clear a field (stored as null).
router.patch('/:id', async (req, res) => {
  const pool = req.app.get('pool');
  const ALLOWED = ['description', 'license', 'copyright_holder', 'source_url', 'uploader'];
  const setClauses = [];
  const values = [];
  for (const key of ALLOWED) {
    if (key in req.body) {
      values.push(req.body[key] || null);
      setClauses.push(`${key} = $${values.length}`);
    }
  }
  if (setClauses.length === 0) return res.status(400).json({ error: 'No recognised fields to update' });
  values.push(req.params.id);
  try {
    const result = await pool.query(
      `UPDATE shared_assets SET ${setClauses.join(', ')}, updated_at = NOW()
       WHERE id = $${values.length} RETURNING *`,
      values
    );
    if (!result.rows.length) return res.status(404).json({ error: 'Not found' });
    const row = result.rows[0];
    res.json({ asset: { ...row, url: row.minio_object_key ? publicUrl(row.minio_object_key) : null } });
  } catch (err) {
    res.status(500).json({ error: 'Failed to update asset' });
  }
});

// ── DELETE /api/assets/:id ───────────────────────────────────────────────────
router.delete('/:id', async (req, res) => {
  const pool = req.app.get('pool');
  try {
    const result = await pool.query(
      'DELETE FROM shared_assets WHERE id = $1 RETURNING minio_object_key',
      [req.params.id]
    );
    if (!result.rows.length) return res.status(404).json({ error: 'Not found' });

    const { minio_object_key } = result.rows[0];
    if (minio_object_key) {
      await deleteObject(minio_object_key).catch(err =>
        console.warn('MinIO delete failed (continuing):', err.message)
      );
    }
    res.json({ success: true });
  } catch (err) {
    console.error('Delete asset error:', err);
    res.status(500).json({ error: 'Failed to delete asset' });
  }
});

export default router;
