const express = require('express');
const { v4: uuidv4 } = require('uuid');
const router = express.Router();
const slugify = require('slugify');

module.exports = (pool, query, authMiddleware) => {
  // Apply authentication middleware to all routes
  router.use(authMiddleware);
  
  // Get all blog posts (admin)
  router.get('/', async (req, res, next) => {
    try {
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Get all posts with basic info
      const result = await query(`
        SELECT 
          b.id, b.title, b.slug, b.excerpt, b.status, 
          b.featured_image_path, b.published_at, b.created_at,
          u.first_name as author_first_name, u.last_name as author_last_name,
          bc.name as category_name
        FROM blog_posts b
        LEFT JOIN users u ON b.author_id = u.id
        LEFT JOIN blog_categories bc ON b.category_id = bc.id
        ORDER BY 
          CASE WHEN b.status = 'draft' THEN 1
               WHEN b.status = 'published' THEN 2
               ELSE 3
          END,
          b.created_at DESC
      `);
      
      res.json(result.rows);
    } catch (error) {
      next(error);
    }
  });
  
  // Get single blog post for editing (admin)
  router.get('/:id', async (req, res, next) => {
    try {
      const { id } = req.params;
      
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Get post with all details
      const postQuery = `
        SELECT 
          b.id, b.title, b.slug, b.content, b.excerpt, 
          b.featured_image_path, b.status, b.published_at, 
          b.created_at, b.updated_at, b.author_id, b.category_id,
          u.first_name as author_first_name, u.last_name as author_last_name,
          bc.name as category_name,
          ARRAY_AGG(DISTINCT t.name) FILTER (WHERE t.name IS NOT NULL) AS tags
        FROM blog_posts b
        LEFT JOIN users u ON b.author_id = u.id
        LEFT JOIN blog_categories bc ON b.category_id = bc.id
        LEFT JOIN blog_post_tags bpt ON b.id = bpt.post_id
        LEFT JOIN tags t ON bpt.tag_id = t.id
        WHERE b.id = $1
        GROUP BY b.id, u.id, bc.id
      `;
      
      const postResult = await query(postQuery, [id]);
      
      if (postResult.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Blog post not found'
        });
      }
      
      const post = postResult.rows[0];
      
      // Get post images
      const imagesQuery = `
        SELECT id, image_path, caption, display_order
        FROM blog_post_images
        WHERE post_id = $1
        ORDER BY display_order
      `;
      
      const imagesResult = await query(imagesQuery, [id]);
      
      // Return the post with images
      res.json({
        ...post,
        images: imagesResult.rows
      });
    } catch (error) {
      next(error);
    }
  });
  
  // Create a new blog post
  router.post('/', async (req, res, next) => {
    try {
      const { 
        title, content, excerpt, categoryId, 
        tags, featuredImagePath, status, publishNow
      } = req.body;
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Validate required fields
      if (!title || !content) {
        return res.status(400).json({
          error: true,
          message: 'Title and content are required'
        });
      }
      
      // Generate slug from title
      let slug = slugify(title, {
        lower: true,      // convert to lower case
        strict: true,     // strip special characters
        remove: /[*+~.()'"!:@]/g  // regex to remove characters
      });
      
      const slugCheck = await query(
        'SELECT id FROM blog_posts WHERE slug = $1',
        [slug]
      );
      
      // If slug exists, append a random string
      if (slugCheck.rows.length > 0) {
        const randomString = Math.random().toString(36).substring(2, 8);
        slug = `${slug}-${randomString}`;
      }
      
      // Begin transaction
      const client = await pool.connect();
      
      try {
        await client.query('BEGIN');
        
        // Set published_at date if publishing now
        const publishedAt = (status === 'published' && publishNow) ? new Date() : null;
        
        // Create the post
        const postId = uuidv4();
        const postResult = await client.query(
          `INSERT INTO blog_posts
           (id, title, slug, content, excerpt, author_id, category_id, status, featured_image_path, published_at)
           VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
           RETURNING *`,
          [postId, title, slug, content, excerpt || null, req.user.id, categoryId || null, 
           status || 'draft', featuredImagePath || null, publishedAt]
        );
        
        // Add tags if provided
        if (tags && Array.isArray(tags) && tags.length > 0) {
          for (const tagName of tags) {
            // Get or create tag
            let tagId;
            const tagResult = await client.query(
              'SELECT id FROM tags WHERE name = $1',
              [tagName]
            );
            
            if (tagResult.rows.length > 0) {
              tagId = tagResult.rows[0].id;
            } else {
              const newTagResult = await client.query(
                'INSERT INTO tags (id, name) VALUES ($1, $2) RETURNING id',
                [uuidv4(), tagName]
              );
              tagId = newTagResult.rows[0].id;
            }
            
            // Add tag to post
            await client.query(
              'INSERT INTO blog_post_tags (post_id, tag_id) VALUES ($1, $2)',
              [postId, tagId]
            );
          }
        }
        
        await client.query('COMMIT');
        
        res.status(201).json({
          message: 'Blog post created successfully',
          post: postResult.rows[0]
        });
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    } catch (error) {
      next(error);
    }
  });
  
  // Update blog post
  router.put('/:id', async (req, res, next) => {
    try {
      const { id } = req.params;
      const { 
        title, content, excerpt, categoryId, 
        tags, featuredImagePath, status, publishNow
      } = req.body;
      
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Validate required fields
      if (!title || !content) {
        return res.status(400).json({
          error: true,
          message: 'Title and content are required'
        });
      }
      
      // Check if post exists
      const postCheck = await query(
        'SELECT id, slug, status, published_at FROM blog_posts WHERE id = $1',
        [id]
      );
      
      if (postCheck.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Blog post not found'
        });
      }
      
      const existingPost = postCheck.rows[0];
      let updatedSlug = existingPost.slug;
      
      // Update slug if title changed
      if (title) {
        const newSlug = slugify(title, {
          lower: true,
          strict: true,
          remove: /[*+~.()'"!:@]/g
        });
        
        // Only update slug if it's different
        if (newSlug !== existingPost.slug) {
          // Check if new slug already exists
          const slugCheck = await query(
            'SELECT id FROM blog_posts WHERE slug = $1 AND id != $2',
            [newSlug, id]
          );
          
          if (slugCheck.rows.length === 0) {
            updatedSlug = newSlug;
          } else {
            // Append random string to slug
            const randomString = Math.random().toString(36).substring(2, 8);
            updatedSlug = `${newSlug}-${randomString}`;
          }
        }
      }
      
      // Begin transaction
      const client = await pool.connect();
      
      try {
        await client.query('BEGIN');
        
        // Determine published_at date
        let publishedAt = existingPost.published_at;
        if (status === 'published' && publishNow && !existingPost.published_at) {
          publishedAt = new Date();
        }
        
        // Update the post
        const postResult = await client.query(
          `UPDATE blog_posts SET
           title = $1, 
           slug = $2, 
           content = $3, 
           excerpt = $4,
           category_id = $5,
           status = $6,
           featured_image_path = $7,
           published_at = $8,
           updated_at = NOW()
           WHERE id = $9
           RETURNING *`,
          [title, updatedSlug, content, excerpt || null, categoryId || null, 
           status || existingPost.status, featuredImagePath, publishedAt, id]
        );
        
        // Update tags if provided
        if (tags !== undefined) {
          // Remove existing tags
          await client.query('DELETE FROM blog_post_tags WHERE post_id = $1', [id]);
          
          // Add new tags
          if (Array.isArray(tags) && tags.length > 0) {
            for (const tagName of tags) {
              // Get or create tag
              let tagId;
              const tagResult = await client.query(
                'SELECT id FROM tags WHERE name = $1',
                [tagName]
              );
              
              if (tagResult.rows.length > 0) {
                tagId = tagResult.rows[0].id;
              } else {
                const newTagResult = await client.query(
                  'INSERT INTO tags (id, name) VALUES ($1, $2) RETURNING id',
                  [uuidv4(), tagName]
                );
                tagId = newTagResult.rows[0].id;
              }
              
              // Add tag to post
              await client.query(
                'INSERT INTO blog_post_tags (post_id, tag_id) VALUES ($1, $2)',
                [id, tagId]
              );
            }
          }
        }
        
        await client.query('COMMIT');
        
        res.json({
          message: 'Blog post updated successfully',
          post: postResult.rows[0]
        });
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    } catch (error) {
      next(error);
    }
  });
  
  // Delete blog post
  router.delete('/:id', async (req, res, next) => {
    try {
      const { id } = req.params;
      
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Check if post exists
      const postCheck = await query(
        'SELECT id FROM blog_posts WHERE id = $1',
        [id]
      );
      
      if (postCheck.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Blog post not found'
        });
      }
      
      // Delete post - cascade will handle related records
      await query(
        'DELETE FROM blog_posts WHERE id = $1',
        [id]
      );
      
      res.json({
        message: 'Blog post deleted successfully'
      });
    } catch (error) {
      next(error);
    }
  });
  
  // Upload blog post image
  router.post('/:postId/images', async (req, res, next) => {
    try {
      const { postId } = req.params;
      const { imagePath, caption, displayOrder } = req.body;
      
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Check if post exists
      const postCheck = await query(
        'SELECT id FROM blog_posts WHERE id = $1',
        [postId]
      );
      
      if (postCheck.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Blog post not found'
        });
      }
      
      // Check if image path is provided
      if (!imagePath) {
        return res.status(400).json({
          error: true,
          message: 'Image path is required'
        });
      }
      
      // Add image to post
      const result = await query(
        `INSERT INTO blog_post_images (id, post_id, image_path, caption, display_order)
         VALUES ($1, $2, $3, $4, $5)
         RETURNING *`,
        [uuidv4(), postId, imagePath, caption || null, displayOrder || 0]
      );
      
      res.status(201).json({
        message: 'Image added to blog post',
        image: result.rows[0]
      });
    } catch (error) {
      next(error);
    }
  });
  
  // Delete blog post image
  router.delete('/:postId/images/:imageId', async (req, res, next) => {
    try {
      const { postId, imageId } = req.params;
      
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Check if image exists and belongs to post
      const imageCheck = await query(
        'SELECT id FROM blog_post_images WHERE id = $1 AND post_id = $2',
        [imageId, postId]
      );
      
      if (imageCheck.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Image not found or does not belong to this post'
        });
      }
      
      // Delete image
      await query(
        'DELETE FROM blog_post_images WHERE id = $1',
        [imageId]
      );
      
      res.json({
        message: 'Image deleted successfully'
      });
    } catch (error) {
      next(error);
    }
  });
  
  return router;
};