import { Router, Response } from 'express';
import multer from 'multer';
import path from 'path';
import { pool } from '../db/pool.js';
import { authMiddleware, AuthenticatedRequest } from '../middleware/auth.js';
import { getStorageProvider } from '../services/storage/factory.js';

const router = Router();

const upload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 50 * 1024 * 1024 }, // 50MB max
  fileFilter: (_req, file, cb) => {
    const allowedTypes = [
      'audio/mpeg',
      'audio/wav',
      'audio/flac',
      'audio/mp3',
      'audio/x-wav',
      'audio/x-flac',
      'audio/mp4',
      'audio/x-m4a',
      'audio/aac',
      'video/mp4',
    ];
    if (allowedTypes.includes(file.mimetype) || file.originalname.match(/\.(mp3|wav|flac|m4a|mp4)$/i)) {
      cb(null, true);
    } else {
      cb(new Error('Invalid file type. Only MP3, WAV, FLAC, M4A, and MP4 are allowed.'));
    }
  }
});

// Get user's reference tracks
router.get('/', authMiddleware, async (req: AuthenticatedRequest, res: Response) => {
  try {
    const result = await pool.query(
      `SELECT id, filename, storage_key, duration, file_size_bytes, tags, created_at
       FROM reference_tracks
       WHERE user_id = $1
       ORDER BY created_at DESC`,
      [req.user!.id]
    );

    const storage = getStorageProvider();
    const tracks = result.rows.map(row => ({
      ...row,
      audio_url: storage.getPublicUrl(row.storage_key)
    }));

    res.json({ tracks });
  } catch (error) {
    console.error('Get reference tracks error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// Upload a new reference track
router.post('/', authMiddleware, upload.single('audio'), async (req: AuthenticatedRequest, res: Response) => {
  try {
    if (!req.file) {
      res.status(400).json({ error: 'No file uploaded' });
      return;
    }

    const userId = req.user!.id;
    const originalFilename = req.file.originalname;
    const ext = path.extname(originalFilename) || '.mp3';
    const timestamp = Date.now();
    const key = `reference-tracks/${userId}/${timestamp}${ext}`;

    const storage = getStorageProvider();
    await storage.upload(key, req.file.buffer, req.file.mimetype);
    const audioUrl = storage.getPublicUrl(key);

    // Parse tags from request body if provided
    const tags = req.body.tags ? JSON.parse(req.body.tags) : null;

    const result = await pool.query(
      `INSERT INTO reference_tracks (user_id, filename, storage_key, file_size_bytes, tags)
       VALUES ($1, $2, $3, $4, $5)
       RETURNING *`,
      [userId, originalFilename, key, req.file.size, tags]
    );

    res.status(201).json({
      track: {
        ...result.rows[0],
        audio_url: audioUrl
      }
    });
  } catch (error) {
    console.error('Upload reference track error:', error);
    const errorMessage = error instanceof Error ? error.message : 'Unknown error';
    res.status(500).json({ error: 'Failed to upload reference track', details: errorMessage });
  }
});

// Update reference track (duration, tags)
router.patch('/:id', authMiddleware, async (req: AuthenticatedRequest, res: Response) => {
  try {
    // Verify ownership
    const check = await pool.query(
      'SELECT user_id FROM reference_tracks WHERE id = $1',
      [req.params.id]
    );
    if (check.rows.length === 0) {
      res.status(404).json({ error: 'Track not found' });
      return;
    }
    if (check.rows[0].user_id !== req.user!.id) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    const { duration, tags } = req.body;
    const updates: string[] = [];
    const values: unknown[] = [];
    let paramCount = 1;

    if (duration !== undefined) {
      updates.push(`duration = $${paramCount}`);
      values.push(duration);
      paramCount++;
    }
    if (tags !== undefined) {
      updates.push(`tags = $${paramCount}`);
      values.push(tags);
      paramCount++;
    }

    if (updates.length === 0) {
      res.status(400).json({ error: 'No fields to update' });
      return;
    }

    values.push(req.params.id);
    const result = await pool.query(
      `UPDATE reference_tracks SET ${updates.join(', ')} WHERE id = $${paramCount} RETURNING *`,
      values
    );

    const storage = getStorageProvider();
    res.json({
      track: {
        ...result.rows[0],
        audio_url: storage.getPublicUrl(result.rows[0].storage_key)
      }
    });
  } catch (error) {
    console.error('Update reference track error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

// Delete a reference track
router.delete('/:id', authMiddleware, async (req: AuthenticatedRequest, res: Response) => {
  try {
    // Verify ownership
    const check = await pool.query(
      'SELECT user_id, storage_key FROM reference_tracks WHERE id = $1',
      [req.params.id]
    );
    if (check.rows.length === 0) {
      res.status(404).json({ error: 'Track not found' });
      return;
    }
    if (check.rows[0].user_id !== req.user!.id) {
      res.status(403).json({ error: 'Access denied' });
      return;
    }

    // Delete from storage
    const storage = getStorageProvider();
    try {
      await storage.delete(check.rows[0].storage_key);
    } catch (storageError) {
      console.error('Failed to delete from storage:', storageError);
    }

    // Delete from database
    await pool.query('DELETE FROM reference_tracks WHERE id = $1', [req.params.id]);

    res.json({ success: true });
  } catch (error) {
    console.error('Delete reference track error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

export default router;
