import Project from "../models/Project.js";
import logger from "../utils/logger.js";
import {
  getFileUrl,
  deleteFile,
  transformImageUrls,
} from "../middleware/upload.js";
import {
  isValidObjectId,
  isValidLanguage,
  validatePagination,
  isValidStatus,
  sanitizeString,
  validateBilingualTitle,
  validateBilingualDescription,
  escapeRegex,
  validateSearchQuery,
} from "../utils/validation.js";
import { PROJECT_CONSTANTS, SORT_FIELDS } from "../utils/constants.js";

/**
 * Transform project data based on language preference and ensure full image URLs
 * @param {Object} project - Project document
 * @param {String} lang - Language code ('en', 'ar', or null for both)
 * @param {Object} req - Express request object (for building full URLs)
 * @returns {Object} Transformed project object
 */
const transformProjectByLanguage = (project, lang, req = null) => {
  if (!project) return null;

  const projectObj = project.toObject ? project.toObject() : project;

  // Transform image URLs to full URLs
  if (projectObj.images && Array.isArray(projectObj.images)) {
    projectObj.images = transformImageUrls(projectObj.images, req);
  }

  // Validate language parameter
  if (!isValidLanguage(lang)) {
    return projectObj; // Return both languages if invalid lang
  }

  // If no language specified, return both languages
  if (!lang) {
    return projectObj;
  }

  // Transform title and description based on language
  const transformed = {
    ...projectObj,
    title:
      lang === PROJECT_CONSTANTS.LANGUAGE.ENGLISH
        ? projectObj.title.en
        : projectObj.title.ar,
    description:
      lang === PROJECT_CONSTANTS.LANGUAGE.ENGLISH
        ? projectObj.description.en
        : projectObj.description.ar,
  };

  return transformed;
};

/**
 * Build query for projects based on filters and admin status
 */
const buildProjectQuery = (filters, isAdmin = false) => {
  const { status, featuredOnHomepage, search } = filters;
  const query = {};

  // Filter by featured status if provided
  if (featuredOnHomepage !== undefined) {
    query.featuredOnHomepage =
      featuredOnHomepage === "true" || featuredOnHomepage === true;
  } else if (!isAdmin) {
    // If not admin and no featured filter specified, only show featured projects
    query.featuredOnHomepage = true;
  }

  // Filter by status if provided
  if (status && isValidStatus(status)) {
    query.status = status;
  }

  // Add search functionality - searches in both English and Arabic titles
  if (search && search.trim().length > 0) {
    const escapedSearch = escapeRegex(search.trim());
    const searchRegex = new RegExp(escapedSearch, "i"); // Case-insensitive search

    // Search in both English and Arabic titles using $or operator
    query.$or = [{ "title.en": searchRegex }, { "title.ar": searchRegex }];
  }

  return query;
};

/**
 * Cleanup uploaded files on error
 */
const cleanupUploadedFiles = (files) => {
  if (files && files.length > 0) {
    files.forEach((file) => {
      try {
        deleteFile(file.filename);
      } catch (error) {
        logger.error("Failed to delete uploaded file", {
          filename: file.filename,
          error: error.message,
        });
      }
    });
  }
};

/**
 * Get all projects
 * GET /api/projects?lang=en|ar
 * - Featured projects are publicly accessible
 * - Non-featured projects require admin authentication
 * - Supports filtering by status, featuredOnHomepage, search, pagination, and sorting
 */
export const getAllProjects = async (req, res, next) => {
  try {
    const {
      status,
      featuredOnHomepage,
      page,
      limit,
      sortBy = PROJECT_CONSTANTS.DEFAULT_SORT_BY,
      sortOrder = PROJECT_CONSTANTS.DEFAULT_SORT_ORDER,
      lang,
      search, // Search query parameter
    } = req.query;

    // Check if user is authenticated (admin)
    const isAdmin = !!req.admin;

    // Validate language parameter
    if (lang && !isValidLanguage(lang)) {
      return res.status(400).json({
        success: false,
        error: "Invalid language parameter. Use 'en' or 'ar'",
      });
    }

    // Validate search query if provided
    if (search !== undefined) {
      const searchValidation = validateSearchQuery(search);
      if (!searchValidation.valid) {
        return res.status(400).json({
          success: false,
          error: searchValidation.error,
        });
      }
    }

    // Validate sort field
    if (sortBy && !SORT_FIELDS.includes(sortBy)) {
      return res.status(400).json({
        success: false,
        error: `Invalid sort field. Allowed fields: ${SORT_FIELDS.join(", ")}`,
      });
    }

    // Validate sort order
    if (sortOrder && sortOrder !== "asc" && sortOrder !== "desc") {
      return res.status(400).json({
        success: false,
        error: "Invalid sort order. Use 'asc' or 'desc'",
      });
    }

    // Check if requesting non-featured projects without admin authentication
    if (
      featuredOnHomepage === "false" ||
      featuredOnHomepage === false ||
      featuredOnHomepage === "0"
    ) {
      if (!isAdmin) {
        return res.status(403).json({
          success: false,
          error:
            "Access denied. Only admins can view non-featured projects. Please authenticate with admin credentials.",
        });
      }
    }

    // Build query with search
    const query = buildProjectQuery(
      {
        status,
        featuredOnHomepage,
        search: search ? search.trim() : undefined,
      },
      isAdmin
    );

    // Validate and calculate pagination
    const pagination = validatePagination(page, limit);

    // Build sort options
    const sortOptions = {};
    sortOptions[sortBy] = sortOrder === "asc" ? 1 : -1;

    // Execute query with lean() for better performance
    const [projects, total] = await Promise.all([
      Project.find(query)
        .populate("createdBy", "name email")
        .sort(sortOptions)
        .skip(pagination.skip)
        .limit(pagination.limit)
        .lean(),
      Project.countDocuments(query),
    ]);

    // Transform projects based on language preference and ensure full image URLs
    const transformedProjects = projects
      .map((project) => transformProjectByLanguage(project, lang, req))
      .filter((project) => project !== null);

    res.status(200).json({
      success: true,
      data: {
        projects: transformedProjects,
        pagination: {
          page: pagination.page,
          limit: pagination.limit,
          total,
          pages: Math.ceil(total / pagination.limit),
        },
        language: lang || PROJECT_CONSTANTS.LANGUAGE.BOTH,
        isAdmin,
        ...(search && { search: search.trim() }), // Include search term in response
      },
    });
  } catch (error) {
    logger.error("Get all projects error", error);
    next(error);
  }
};

/**
 * Get single project by ID
 * GET /api/projects/:id?lang=en|ar
 * - Featured projects are publicly accessible
 * - Non-featured projects require admin authentication
 */
export const getProjectById = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { lang } = req.query;

    // Validate MongoDB ObjectId
    if (!isValidObjectId(id)) {
      return res.status(400).json({
        success: false,
        error: "Invalid project ID format",
      });
    }

    // Validate language parameter
    if (lang && !isValidLanguage(lang)) {
      return res.status(400).json({
        success: false,
        error: "Invalid language parameter. Use 'en' or 'ar'",
      });
    }

    const project = await Project.findById(id)
      .populate("createdBy", "name email")
      .lean();

    if (!project) {
      return res.status(404).json({
        success: false,
        error: "Project not found",
      });
    }

    // Check if user is authenticated (admin)
    const isAdmin = !!req.admin;

    // Only admins can view non-featured projects
    if (!project.featuredOnHomepage && !isAdmin) {
      logger.warn("Unauthorized access attempt to non-featured project", {
        projectId: id,
        srNo: project.srNo,
        featuredOnHomepage: project.featuredOnHomepage,
        ip: req.ip,
      });

      return res.status(403).json({
        success: false,
        error:
          "Access denied. Only admins can view non-featured projects. Please authenticate with admin credentials.",
      });
    }

    // Transform project based on language preference and ensure full image URLs
    const transformedProject = transformProjectByLanguage(project, lang, req);

    res.status(200).json({
      success: true,
      data: {
        project: transformedProject,
        language: lang || PROJECT_CONSTANTS.LANGUAGE.BOTH,
        isAdmin,
      },
    });
  } catch (error) {
    logger.error("Get project by ID error", error);
    next(error);
  }
};

/**
 * Create new project
 * POST /api/projects
 */
export const createProject = async (req, res, next) => {
  try {
    const { title, description, featuredOnHomepage, status } = req.body;

    // Validate title
    const titleValidation = validateBilingualTitle(title);
    if (!titleValidation.valid) {
      cleanupUploadedFiles(req.files);
      return res.status(400).json({
        success: false,
        error: titleValidation.error,
      });
    }

    // Validate description
    const descriptionValidation = validateBilingualDescription(description);
    if (!descriptionValidation.valid) {
      cleanupUploadedFiles(req.files);
      return res.status(400).json({
        success: false,
        error: descriptionValidation.error,
      });
    }

    // Validate status if provided
    if (status && !isValidStatus(status)) {
      cleanupUploadedFiles(req.files);
      return res.status(400).json({
        success: false,
        error: `Invalid status. Must be '${PROJECT_CONSTANTS.STATUS.DRAFT}' or '${PROJECT_CONSTANTS.STATUS.PUBLISHED}'`,
      });
    }

    // Validate image count
    if (
      req.files &&
      req.files.length > PROJECT_CONSTANTS.MAX_IMAGES_PER_PROJECT
    ) {
      cleanupUploadedFiles(req.files);
      return res.status(400).json({
        success: false,
        error: `Maximum ${PROJECT_CONSTANTS.MAX_IMAGES_PER_PROJECT} images allowed per project`,
      });
    }

    // Handle uploaded images with full URLs
    const images = [];
    if (req.files && req.files.length > 0) {
      req.files.forEach((file) => {
        images.push({
          url: getFileUrl(file.filename, req),
          filename: file.filename,
        });
      });
    }

    // Create project
    const project = await Project.create({
      title: {
        en: sanitizeString(title.en),
        ar: sanitizeString(title.ar),
      },
      description: {
        en: sanitizeString(description.en),
        ar: sanitizeString(description.ar),
      },
      images,
      featuredOnHomepage:
        featuredOnHomepage === true || featuredOnHomepage === "true",
      status: status || PROJECT_CONSTANTS.STATUS.DRAFT,
      createdBy: req.admin.id,
    });

    logger.info("Project created successfully", {
      projectId: project._id,
      srNo: project.srNo,
      createdBy: req.admin.email,
    });

    // Transform project to ensure full image URLs
    const projectObj = project.toObject ? project.toObject() : project;
    if (projectObj.images && Array.isArray(projectObj.images)) {
      projectObj.images = transformImageUrls(projectObj.images, req);
    }

    res.status(201).json({
      success: true,
      message: "Project created successfully",
      data: {
        project: projectObj,
      },
    });
  } catch (error) {
    cleanupUploadedFiles(req.files);
    logger.error("Create project error", error);
    next(error);
  }
};

/**
 * Update project
 * PUT /api/projects/:id
 */
export const updateProject = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { title, description, featuredOnHomepage, status, removeImages } =
      req.body;

    // Validate MongoDB ObjectId
    if (!isValidObjectId(id)) {
      cleanupUploadedFiles(req.files);
      return res.status(400).json({
        success: false,
        error: "Invalid project ID format",
      });
    }

    const project = await Project.findById(id);

    if (!project) {
      cleanupUploadedFiles(req.files);
      return res.status(404).json({
        success: false,
        error: "Project not found",
      });
    }

    // Update title if provided
    if (title) {
      const titleValidation = validateBilingualTitle(title);
      if (!titleValidation.valid) {
        cleanupUploadedFiles(req.files);
        return res.status(400).json({
          success: false,
          error: titleValidation.error,
        });
      }
      if (title.en) project.title.en = sanitizeString(title.en);
      if (title.ar) project.title.ar = sanitizeString(title.ar);
    }

    // Update description if provided
    if (description) {
      const descriptionValidation = validateBilingualDescription(description);
      if (!descriptionValidation.valid) {
        cleanupUploadedFiles(req.files);
        return res.status(400).json({
          success: false,
          error: descriptionValidation.error,
        });
      }
      if (description.en)
        project.description.en = sanitizeString(description.en);
      if (description.ar)
        project.description.ar = sanitizeString(description.ar);
    }

    // Update featuredOnHomepage if provided
    if (featuredOnHomepage !== undefined) {
      project.featuredOnHomepage =
        featuredOnHomepage === true || featuredOnHomepage === "true";
    }

    // Update status if provided
    if (status) {
      if (!isValidStatus(status)) {
        cleanupUploadedFiles(req.files);
        return res.status(400).json({
          success: false,
          error: `Invalid status. Must be '${PROJECT_CONSTANTS.STATUS.DRAFT}' or '${PROJECT_CONSTANTS.STATUS.PUBLISHED}'`,
        });
      }
      project.status = status;
    }

    // Handle new image uploads with full URLs
    if (req.files && req.files.length > 0) {
      const newImages = req.files.map((file) => ({
        url: getFileUrl(file.filename, req),
        filename: file.filename,
      }));

      // Check total images limit
      const totalImages = project.images.length + newImages.length;
      if (totalImages > PROJECT_CONSTANTS.MAX_IMAGES_PER_PROJECT) {
        cleanupUploadedFiles(req.files);
        return res.status(400).json({
          success: false,
          error: `Maximum ${PROJECT_CONSTANTS.MAX_IMAGES_PER_PROJECT} images allowed per project`,
        });
      }

      project.images.push(...newImages);
    }

    // Handle image removal
    if (removeImages) {
      let imagesToRemove = removeImages;

      // Handle both array and string (JSON) formats
      if (typeof removeImages === "string") {
        try {
          imagesToRemove = JSON.parse(removeImages);
        } catch (error) {
          cleanupUploadedFiles(req.files);
          return res.status(400).json({
            success: false,
            error:
              "Invalid removeImages format. Must be an array or JSON string",
          });
        }
      }

      if (Array.isArray(imagesToRemove)) {
        imagesToRemove.forEach((filename) => {
          if (typeof filename === "string") {
            const imageIndex = project.images.findIndex(
              (img) => img.filename === filename
            );
            if (imageIndex !== -1) {
              try {
                deleteFile(filename);
                project.images.splice(imageIndex, 1);
              } catch (error) {
                logger.warn("Failed to delete image file", {
                  filename,
                  error: error.message,
                });
              }
            }
          }
        });
      }
    }

    await project.save();

    logger.info("Project updated successfully", {
      projectId: project._id,
      srNo: project.srNo,
      updatedBy: req.admin.email,
    });

    // Transform project to ensure full image URLs
    const projectObj = project.toObject ? project.toObject() : project;
    if (projectObj.images && Array.isArray(projectObj.images)) {
      projectObj.images = transformImageUrls(projectObj.images, req);
    }

    res.status(200).json({
      success: true,
      message: "Project updated successfully",
      data: {
        project: projectObj,
      },
    });
  } catch (error) {
    cleanupUploadedFiles(req.files);
    logger.error("Update project error", error);
    next(error);
  }
};

/**
 * Delete project
 * DELETE /api/projects/:id
 */
export const deleteProject = async (req, res, next) => {
  try {
    const { id } = req.params;

    // Validate MongoDB ObjectId
    if (!isValidObjectId(id)) {
      return res.status(400).json({
        success: false,
        error: "Invalid project ID format",
      });
    }

    const project = await Project.findById(id);

    if (!project) {
      return res.status(404).json({
        success: false,
        error: "Project not found",
      });
    }

    // Delete all associated images
    if (project.images && project.images.length > 0) {
      project.images.forEach((image) => {
        try {
          deleteFile(image.filename);
        } catch (error) {
          logger.warn("Failed to delete image file during project deletion", {
            filename: image.filename,
            projectId: id,
            error: error.message,
          });
        }
      });
    }

    // Delete project
    await Project.findByIdAndDelete(id);

    logger.info("Project deleted successfully", {
      projectId: id,
      srNo: project.srNo,
      deletedBy: req.admin.email,
      imagesDeleted: project.images?.length || 0,
    });

    res.status(200).json({
      success: true,
      message: "Project deleted successfully",
    });
  } catch (error) {
    logger.error("Delete project error", error);
    next(error);
  }
};

/**
 * Toggle featured on homepage
 * PATCH /api/projects/:id/feature
 */
export const toggleFeatured = async (req, res, next) => {
  try {
    const { id } = req.params;

    // Validate MongoDB ObjectId
    if (!isValidObjectId(id)) {
      return res.status(400).json({
        success: false,
        error: "Invalid project ID format",
      });
    }

    const project = await Project.findById(id);

    if (!project) {
      return res.status(404).json({
        success: false,
        error: "Project not found",
      });
    }

    const previousStatus = project.featuredOnHomepage;
    project.featuredOnHomepage = !project.featuredOnHomepage;
    await project.save();

    logger.info("Project featured status toggled", {
      projectId: project._id,
      srNo: project.srNo,
      previousStatus,
      newStatus: project.featuredOnHomepage,
      toggledBy: req.admin.email,
    });

    // Transform project to ensure full image URLs
    const projectObj = project.toObject ? project.toObject() : project;
    if (projectObj.images && Array.isArray(projectObj.images)) {
      projectObj.images = transformImageUrls(projectObj.images, req);
    }

    res.status(200).json({
      success: true,
      message: `Project ${
        project.featuredOnHomepage ? "featured" : "unfeatured"
      } successfully`,
      data: {
        project: projectObj,
      },
    });
  } catch (error) {
    logger.error("Toggle featured error", error);
    next(error);
  }
};

/**
 * Toggle publish status
 * PATCH /api/projects/:id/publish
 */
export const togglePublish = async (req, res, next) => {
  try {
    const { id } = req.params;

    // Validate MongoDB ObjectId
    if (!isValidObjectId(id)) {
      return res.status(400).json({
        success: false,
        error: "Invalid project ID format",
      });
    }

    const project = await Project.findById(id);

    if (!project) {
      return res.status(404).json({
        success: false,
        error: "Project not found",
      });
    }

    const previousStatus = project.status;
    // Toggle between draft and published
    project.status =
      project.status === PROJECT_CONSTANTS.STATUS.PUBLISHED
        ? PROJECT_CONSTANTS.STATUS.DRAFT
        : PROJECT_CONSTANTS.STATUS.PUBLISHED;
    await project.save();

    logger.info("Project publish status toggled", {
      projectId: project._id,
      srNo: project.srNo,
      previousStatus,
      newStatus: project.status,
      toggledBy: req.admin.email,
    });

    // Transform project to ensure full image URLs
    const projectObj = project.toObject ? project.toObject() : project;
    if (projectObj.images && Array.isArray(projectObj.images)) {
      projectObj.images = transformImageUrls(projectObj.images, req);
    }

    res.status(200).json({
      success: true,
      message: `Project ${
        project.status === PROJECT_CONSTANTS.STATUS.PUBLISHED
          ? "published"
          : "unpublished"
      } successfully`,
      data: {
        project: projectObj,
      },
    });
  } catch (error) {
    logger.error("Toggle publish error", error);
    next(error);
  }
};
