const asyncHandler = require("express-async-handler");
const Blog = require("../models/blogModel");
const BlogModel = new Blog();
const S3Helper = require("../helpers/s3Helper");
const bucket = process.env.AWS_BUCKET;
const pool = require("../config/dbConnection"); // Import the database pool
const sharp = require('sharp');
const Response = require("../helpers/responseHelper");

const extractS3Key = (value) => {
  if (!value) return null;
  let key = value.trim();
  if (!key) return null;

  try {
    const parsed = new URL(key);
    key = parsed.pathname || '';
  } catch (_) {
    if (key.includes('.com/')) {
      key = key.split('.com/')[1];
    }
  }

  key = key.replace(/^\/+/, '');
  const queryIndex = key.indexOf('?');
  if (queryIndex !== -1) {
    key = key.substring(0, queryIndex);
  }

  return key || null;
};

const buildBlogImageUrl = (req, key) => {
  const protocol = req.get('x-forwarded-proto') || req.protocol;
  const host = req.get('host');
  return `${protocol}://${host}/api/blogs/images/${encodeURIComponent(key)}`;
};

const uploadBlogImage = asyncHandler(async (req, res) => {
  if (!req.file) {
    return Response.error(res, "IMAGE_FILE_REQUIRED", "Image file is required.", 400);
  }

  try {
    const featured_image = req.file;
    const now = new Date();
    const formattedDate = now.toISOString().replace(/:/g, '-').replace(/\..+/, '');
    const photoKey = `blogs/${formattedDate}_${featured_image.originalname}`;
    const resizedImageBuffer = await sharp(featured_image.buffer).resize(1280, null).toBuffer();
    const uploadResult = await S3Helper.uploadFile(bucket, photoKey, resizedImageBuffer, {
      ContentType: featured_image.mimetype,
    });

    if (!uploadResult) {
      throw new Error("Failed to upload image to storage.");
    }

    const publicUrl = buildBlogImageUrl(req, photoKey);
return Response.success(res, {
  key: photoKey,
  imageUrl: publicUrl,
  url: publicUrl,
});

  } catch (error) {
    console.error("Error in uploadBlogImage:", error);
    return Response.error(res, "IMAGE_UPLOAD_FAILED", "Failed to upload blog image: " + error.message, 500);
  }
});

const createBlog = asyncHandler(async (req, res) => {
  const { title, content, category, meta_tags, keywords, qa_section, written_by } = req.body; // Added qa_section and written_by
  const author_id = req.user.id;
  let featured_image_url = null;

  if (!title || !content) {
   return Response.error(
  res,
  "VALIDATION_ERROR",
  "Please fill all required fields!",
  400
);

  }

  try {
    if (req.file) {
      const featured_image = req.file;
      const now = new Date();
      const formattedDate = now.toISOString().replace(/:/g, '-').replace(/\..+/, '');
      const photoKey = `blogs/${formattedDate}_${featured_image.originalname}`;
      const resizedImageBuffer = await sharp(featured_image.buffer).resize(1280, null).toBuffer();
      await S3Helper.uploadFile(bucket, photoKey, resizedImageBuffer, {
        ContentType: featured_image.mimetype,
      });
      featured_image_url = photoKey;
    }

    const blog = await BlogModel.create({ title, content, author_id, category, meta_tags, keywords, qa_section, featured_image: featured_image_url, written_by }); // Added qa_section and written_by

    res.status(201).json(blog);
  } catch (error) {
    console.error("Error in createBlog:", error); // Keep error log for production debugging
    return Response.error(res, "BLOG_CREATION_FAILED", "Failed to create blog post: " + error.message, 500);
  }
});

const serveBlogImage = asyncHandler(async (req, res) => {
  const rawKey = req.params.key;
  if (!rawKey) {
    return Response.error(res, "IMAGE_KEY_REQUIRED", "Image key is required.", 400);
  }

  const key = decodeURIComponent(rawKey);

  try {
    const file = await S3Helper.getObject(bucket, key);
    res.set('Content-Type', file.ContentType || 'application/octet-stream');
    res.set('Cache-Control', 'public, max-age=31536000, immutable');
    res.send(file.Body);
  } catch (error) {
    console.error("Error serving blog image:", error);
    return Response.error(res, "IMAGE_NOT_FOUND", "Image not found", 404);
  }
});

const getBlogs = asyncHandler(async (req, res) => {
  try {
    const blogs = await BlogModel.getAll();
    for (let i = 0; i < blogs.length; i++) {
      const key = extractS3Key(blogs[i].featured_image);
      blogs[i].featured_image_key = key;
      if (key) {
        blogs[i].featured_image = buildBlogImageUrl(req, key);
      }
    }
    res.status(200).json(blogs);
  } catch (error) {
    console.error("Error in getBlogs:", error); // Keep error log for production debugging
    return Response.error(res, "BLOG_FETCH_FAILED", "Failed to fetch blogs: " + error.message, 500);
  }
});

const getBlog = asyncHandler(async (req, res) => {
  console.log("getBlog function started. Blog ID:", req.params.id);
  try {
    const blog = await BlogModel.getById(req.params.id);
    if (!blog) {
      return Response.error(res, "BLOG_NOT_FOUND", "Blog not found", 404);
    }

    const key = extractS3Key(blog.featured_image);
    blog.featured_image_key = key;
    if (key) {
      blog.featured_image = buildBlogImageUrl(req, key);
    }

    console.log("Blog fetched from model:", blog);
    console.log("Blog object being sent in response:", blog); // Add this log
    console.log("Response sent from getBlog.");
    return Response.success(res, blog);
  } catch (error) {
    console.error("Error in getBlog:", error);
    return Response.error(res, "BLOG_FETCH_FAILED", "Failed to fetch blog: " + error.message, 500);
  }
});

const updateBlog = asyncHandler(async (req, res) => {
  console.log("updateBlog function started. Blog ID:", req.params.id);
  const author_id = req.user.id;
  const updateFields = {};

  try {
    const blog = await BlogModel.getById(req.params.id);

    if (!blog) {
      return Response.error(res, "BLOG_NOT_FOUND", "Blog not found", 404);
    }

    if (blog.author_id !== author_id) {
      return Response.error(res, "FORBIDDEN", "User doesn't have permission to update other user's blog posts", 403);
    }

    // Handle featured image upload first
    let featuredImageKeyToPersist = null;

    if (req.file) {
      console.log("File detected for update, attempting S3 upload.");
      const featured_image = req.file;
      const now = new Date();
      const formattedDate = now.toISOString().replace(/:/g, '-').replace(/\..+/, '');
      const photoKey = `blogs/${formattedDate}_${featured_image.originalname}`;
      const resizedImageBuffer = await sharp(featured_image.buffer).resize(1280, null).toBuffer();
      await S3Helper.uploadFile(bucket, photoKey, resizedImageBuffer, {
        ContentType: featured_image.mimetype,
      });
      featuredImageKeyToPersist = photoKey;
      console.log("S3 upload successful for update. Key:", featuredImageKeyToPersist);
    } else if (req.body.featured_image === 'null' || req.body.featured_image === '') { // Frontend might send 'null' string or empty string to clear
      updateFields.featured_image = null;
    } else if (req.body.featured_image_key_to_retain || req.body.featured_image_key || req.body.featured_image_url_to_retain) {
      const retainedValue =
        req.body.featured_image_key_to_retain ||
        req.body.featured_image_key ||
        req.body.featured_image_url_to_retain;
      featuredImageKeyToPersist = extractS3Key(retainedValue);
    }

    if (featuredImageKeyToPersist) {
      updateFields.featured_image = featuredImageKeyToPersist;
    }


    // Dynamically add other fields to updateFields if they are present in req.body
    if (req.body.title !== undefined) updateFields.title = req.body.title;
    if (req.body.content !== undefined) updateFields.content = req.body.content;
    if (req.body.category !== undefined) updateFields.category = req.body.category;
    if (req.body.meta_tags !== undefined) updateFields.meta_tags = req.body.meta_tags;
    if (req.body.keywords !== undefined) updateFields.keywords = req.body.keywords;
    if (req.body.active !== undefined) updateFields.active = req.body.active;
    if (req.body.written_by !== undefined) updateFields.written_by = req.body.written_by;

    // Handle qa_section - it comes as a JSON string from formData
    if (req.body.qa_section !== undefined) {
      console.log("Received qa_section from frontend:", req.body.qa_section); // Log the raw input
      try {
        const parsedQa = JSON.parse(req.body.qa_section);
        // If the parsed array is empty or contains only empty objects, store as NULL
        if (Array.isArray(parsedQa) && parsedQa.every(item => !item.question && !item.answer)) {
          updateFields.qa_section = null;
        } else {
          updateFields.qa_section = parsedQa;
        }
      } catch (e) {
        console.error("Error parsing qa_section JSON:", e);
        console.error("Problematic qa_section value:", req.body.qa_section); // Log the problematic value
        return Response.error(res, "INVALID_JSON", "Invalid JSON format for Q&A section.", 400);
      }
    }

    // Ensure there's something to update
    if (Object.keys(updateFields).length === 0) {
      return Response.error(res, "NO_FIELDS_TO_UPDATE", "No fields provided for update.", 400);
    }

    const updatedBlog = await BlogModel.update(req.params.id, updateFields);
    console.log("Blog updated in database. Blog ID:", req.params.id);

    console.log("Response sent from updateBlog.");
return Response.success(res, updatedBlog);
  } catch (error) {
    console.error("Error in updateBlog:", error);
    return Response.error(res, "INTERNAL_SERVER_ERROR", "Failed to update blog post: " + error.message, 500);
  }
});

const deleteBlog = asyncHandler(async (req, res) => {
  console.log("deleteBlog function started. Blog ID:", req.params.id);
  const author_id = req.user.id;

  try {
    const blog = await BlogModel.getById(req.params.id);

    if (!blog) {
      return Response.error(res, "BLOG_NOT_FOUND", "Blog not found", 404);
    }

    if (blog.author_id !== author_id) {
      return Response.error(res, "FORBIDDEN", "User doesn't have permission to delete other user's blog posts", 403);
    }

    await BlogModel.delete({ id: req.params.id }); // Pass id as an object for the where clause
    console.log("Blog deleted from database. Blog ID:", req.params.id);

    console.log("Response sent from deleteBlog.");
   return Response.success(res, { message: "Blog post deleted successfully" });
  } catch (error) {
    console.error("Error in deleteBlog:", error);
    return Response.error(res, "INTERNAL_SERVER_ERROR", "Failed to delete blog post: " + error.message, 500);
  }
});

const getCategories = asyncHandler(async (req, res) => {
  try {
    // Assuming BlogModel has a method to get unique categories
    // If not, we'll need to add one to BaseModel or BlogModel
    const [rows] = await pool.query('SELECT DISTINCT category FROM blogs WHERE category IS NOT NULL AND category != ""');
    const categories = rows.map(row => row.category);
    console.log("Categories fetched:", categories); // Add this log
    return Response.success(res, categories);
  } catch (error) {
    console.error("Error in getCategories:", error);
    return Response.error(res, "INTERNAL_SERVER_ERROR", "Failed to fetch categories: " + error.message, 500);
  }
});

module.exports = { createBlog, getBlogs, getBlog, updateBlog, deleteBlog, getCategories, uploadBlogImage, serveBlogImage };
