const mongoose = require("mongoose");
const path = require("path");
const fs = require('fs');
const Library = require("../models/Library");
const Company = require("../models/Company");
const Role = require("../models/Role");
const ActivityLog = require("../models/ActivityLog");
const LibraryView = require("../models/LibraryView");
const User = require("../models/User");
// const { sendEmail } = require("../utils/emailService");

/**
 * ✅ Get document type based on mimeType or extension
 */
const getDocumentType = (mimeType, extension) => {
  if (!mimeType && !extension) return "other";

  const mime = mimeType ? mimeType.toLowerCase() : "";
  const ext = extension ? extension.toLowerCase() : "";

  // Image
  if (mime.startsWith("image/") || ["jpg", "jpeg", "png", "gif", "svg", "webp", "bmp"].includes(ext)) {
    return "image";
  }

  // Video
  if (mime.startsWith("video/") || ["mp4", "mov", "avi", "mkv", "webm", "flv", "wmv"].includes(ext)) {
    return "video";
  }

  // Audio
  if (mime.startsWith("audio/") || ["mp3", "wav", "ogg", "m4a", "flac", "aac"].includes(ext)) {
    return "audio";
  }

  // Spreadsheet
  if (
    mime === "application/vnd.ms-excel" ||
    mime === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
    mime === "text/csv" ||
    ["xls", "xlsx", "csv", "ods"].includes(ext)
  ) {
    return "spreadsheet";
  }

  // Presentation
  if (
    mime === "application/vnd.ms-powerpoint" ||
    mime === "application/vnd.openxmlformats-officedocument.presentationml.presentation" ||
    ["ppt", "pptx", "odp"].includes(ext)
  ) {
    return "presentation";
  }

  // Archive
  if (
    mime === "application/zip" ||
    mime === "application/x-rar-compressed" ||
    mime === "application/x-7z-compressed" ||
    mime === "application/x-tar" ||
    mime === "application/x-gzip" ||
    ["zip", "rar", "7z", "tar", "gz"].includes(ext)
  ) {
    return "archive";
  }

  // Document (PDF, Word, Text, etc.)
  if (
    mime === "application/pdf" ||
    mime === "application/msword" ||
    mime === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ||
    mime === "text/plain" ||
    mime === "application/rtf" ||
    ["pdf", "doc", "docx", "txt", "rtf", "odt"].includes(ext)
  ) {
    return "document";
  }

  return "other";
};

/**
 * ✅ Validate companyId
 */
const validateCompanyId = async (companyId) => {
  if (!companyId) return { valid: false, message: "companyId is required" };

  if (!mongoose.Types.ObjectId.isValid(companyId)) {
    return { valid: false, message: "Invalid companyId format" };
  }

  const company = await Company.findById(companyId);
  if (!company) {
    return { valid: false, message: "Company not found" };
  }

  return { valid: true, company };
};

/**
 * ✅ Check if user has access to companyId
 */
const checkUserCompanyAccess = async (req, companyId) => {
  const userRole = await Role.findById(req.user.roleId);

  if (!userRole) {
    return { allowed: false, message: "Role not found" };
  }

  // Global can access any company
  if (userRole.scope === "global") {
    return { allowed: true, userRole };
  }

  // Company / Partner must have that company in their companies array
  const userCompanies = (req.user.companies || []).map((c) => c._id.toString());

  if (!userCompanies.includes(companyId.toString())) {
    return {
      allowed: false,
      message: "You do not have access to this company",
    };
  }

  return { allowed: true, userRole };
};

// ✅ Get all library items
exports.getAllLibraryItems = async (req, res, next) => {
  try {
    const {
      companyId,
      category,
      search,
      tags,
      status,
      page = 1,
      limit = 20,
      sortBy = "createdAt",
      sortOrder = "desc",
    } = req.query;

    let query = {};

    const userRole = await Role.findById(req.user.roleId);
    if (!userRole) {
      return res.status(400).json({
        success: false,
        message: "Role not found",
      });
    }

    /**
     * ✅ COMPANY FILTER LOGIC
     * - company/partner => only their companies
     * - global => optional companyId filter
     */
    if (userRole.scope === "company" || userRole.scope === "partner") {
      if (companyId) {
        const companyValidation = await validateCompanyId(companyId);
        if (!companyValidation.valid) {
          return res.status(400).json({
            success: false,
            message: companyValidation.message,
          });
        }

        const accessCheck = await checkUserCompanyAccess(req, companyId);
        if (!accessCheck.allowed) {
          return res.status(403).json({
            success: false,
            message: accessCheck.message,
          });
        }

        query.companyId = companyId;
      } else {
        query.companyId = { $in: req.user.companies };
      }
    }

    if (userRole.scope === "global") {
      if (companyId) {
        const companyValidation = await validateCompanyId(companyId);
        if (!companyValidation.valid) {
          return res.status(400).json({
            success: false,
            message: companyValidation.message,
          });
        }
        query.companyId = companyId;
      }
    }

    if (category) query.category = category;

    if (status) {
      query.status = status;
    } else {
      query.status = { $ne: "deleted" };
    }

    if (tags) {
      query.tags = { $in: tags.split(",").map((t) => t.trim()) };
    }

    if (search) {
      query.$or = [
        { title: { $regex: search, $options: "i" } },
        { description: { $regex: search, $options: "i" } },
        { category: { $regex: search, $options: "i" } },
        { tags: { $in: [new RegExp(search, "i")] } },
      ];
    }

    const skip = (parseInt(page) - 1) * parseInt(limit);

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

    const items = await Library.find(query)
      .populate("companyId", "name code")
      .populate("createdBy", "firstName lastName email")
      .populate("updatedBy", "firstName lastName email")
      .sort(sort)
      .limit(parseInt(limit))
      .skip(skip);

    const total = await Library.countDocuments(query);

    return res.status(200).json({
      success: true,
      count: items.length,
      total,
      page: parseInt(page),
      pages: Math.ceil(total / limit),
      data: items,
    });
  } catch (error) {
    next(error);
  }
};

// ✅ Get library items by companyId (separate API)
exports.getLibraryByCompanyId = async (req, res, next) => {
  try {
    const { companyId } = req.params;

    const {
      category,
      search,
      tags,
      status,
      page = 1,
      limit = 20,
      sortBy = "createdAt",
      sortOrder = "desc",
    } = req.query;

    // ✅ Validate companyId
    const companyValidation = await validateCompanyId(companyId);
    if (!companyValidation.valid) {
      return res.status(400).json({
        success: false,
        message: companyValidation.message,
      });
    }

    // ✅ Check access
    const accessCheck = await checkUserCompanyAccess(req, companyId);
    if (!accessCheck.allowed) {
      return res.status(403).json({
        success: false,
        message: accessCheck.message,
      });
    }

    // ✅ Query filter
    let query = { companyId };

    if (category) query.category = category;

    if (status) {
      query.status = status;
    } else {
      query.status = { $ne: "deleted" };
    }

    if (tags) {
      query.tags = { $in: tags.split(",").map((t) => t.trim()) };
    }

    if (search) {
      query.$or = [
        { title: { $regex: search, $options: "i" } },
        { description: { $regex: search, $options: "i" } },
        { category: { $regex: search, $options: "i" } },
        { tags: { $in: [new RegExp(search, "i")] } },
      ];
    }

    const skip = (parseInt(page) - 1) * parseInt(limit);

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

    const items = await Library.find(query)
      .populate("companyId", "name code")
      .populate("createdBy", "firstName lastName email")
      .populate("updatedBy", "firstName lastName email")
      .sort(sort)
      .limit(parseInt(limit))
      .skip(skip);

    const total = await Library.countDocuments(query);

    // ✅ Update LibraryView to mark as seen
    await LibraryView.findOneAndUpdate(
      { userId: req.user._id, companyId },
      { lastViewedAt: new Date() },
      { upsert: true, new: true }
    );

    return res.status(200).json({
      success: true,
      count: items.length,
      total,
      page: parseInt(page),
      pages: Math.ceil(total / limit),
      data: items,
    });
  } catch (error) {
    next(error);
  }
};

/**
 * ✅ Get unseen counts for Marcom Library for the current user
 */
exports.getUnseenCounts = async (req, res, next) => {
  try {
    let userCompanies = (req.user.companies || []).map(c => c._id || c);

    // ✅ Multi-company access logic:
    // If no companies are assigned, it means "all access" (fetch all active companies)
    if (userCompanies.length === 0) {
      const allCompanies = await Company.find({ status: "active" }).select("_id");
      userCompanies = allCompanies.map(c => c._id);
    }

    // Get last viewed timestamps for this user
    const views = await LibraryView.find({ userId: req.user._id });
    const viewMap = {};
    views.forEach(v => {
      viewMap[v.companyId.toString()] = v.lastViewedAt;
    });

    const counts = {};

    // For each company, count files created after lastViewedAt
    for (const company of userCompanies) {
      const companyId = (company._id || company).toString();
      const lastViewedAt = viewMap[companyId] || new Date(0); // default to epoch if never viewed

      const count = await Library.countDocuments({
        companyId,
        status: { $ne: "deleted" },
        createdBy: { $ne: req.user._id }, // ✅ Except the one who uploaded the file
        createdAt: { $gt: lastViewedAt }
      });

      counts[companyId] = count;
    }

    return res.status(200).json({
      success: true,
      data: counts
    });
  } catch (error) {
    next(error);
  }
};


// ✅ Get single library item
exports.getLibraryItem = async (req, res, next) => {
  try {
    const { id } = req.params;

    if (!mongoose.Types.ObjectId.isValid(id)) {
      return res.status(400).json({
        success: false,
        message: "Invalid library id",
      });
    }

    const item = await Library.findById(id)
      .populate("companyId", "name code")
      .populate("createdBy", "firstName lastName email")
      .populate("updatedBy", "firstName lastName email");

    if (!item) {
      return res.status(404).json({
        success: false,
        message: "Library item not found",
      });
    }

    const accessCheck = await checkUserCompanyAccess(
      req,
      item.companyId.toString()
    );
    if (!accessCheck.allowed) {
      return res.status(403).json({
        success: false,
        message: accessCheck.message,
      });
    }

    return res.status(200).json({
      success: true,
      data: item,
    });
  } catch (error) {
    next(error);
  }
};

exports.downloadLibraryItem = async (req, res, next) => {
  try {
    const { id } = req.params;

    if (!mongoose.Types.ObjectId.isValid(id)) {
      return res.status(400).json({
        success: false,
        message: "Invalid library id",
      });
    }

    const item = await Library.findById(id);

    if (!item) {
      return res.status(404).json({
        success: false,
        message: "Library item not found",
      });
    }

    // ✅ Check user access
    const accessCheck = await checkUserCompanyAccess(req, item.companyId.toString());
    if (!accessCheck.allowed) {
      return res.status(403).json({
        success: false,
        message: accessCheck.message,
      });
    }

    // ✅ Check if file exists
    if (!item.file || !item.file.fileName) {
      return res.status(404).json({
        success: false,
        message: "File not found in database",
      });
    }

    // ✅ Build file path (using process.cwd() for robustness)
    const filePath = path.resolve(process.cwd(), 'uploads', 'library', item.file.fileName);

    // ✅ Check if file exists on disk
    if (!fs.existsSync(filePath)) {
      console.error(`[Download] File not found at path: ${filePath}`);
      return res.status(404).json({
        success: false,
        message: "File not found on server",
      });
    }

    // ✅ Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: item.companyId,
      action: "download",
      module: "library",
      entityType: "Library",
      entityId: item._id,
      description: `Downloaded file: ${item.title}`,
      ipAddress: req.ip,
      userAgent: req.get("user-agent"),
    });

    // ✅ Set headers for download
    res.setHeader('Content-Type', item.file.mimeType || 'application/octet-stream');
    res.setHeader('Content-Disposition', `attachment; filename="${encodeURIComponent(item.file.originalName || item.title)}"`);
    res.setHeader('Content-Length', item.file.size);

    // ✅ Stream file to response
    const fileStream = fs.createReadStream(filePath);
    fileStream.pipe(res);

    fileStream.on('error', (error) => {
      console.error('File stream error:', error);
      res.status(500).json({
        success: false,
        message: "Error streaming file"
      });
    });

  } catch (error) {
    next(error);
  }
};

exports.shareLibraryItem = async (req, res, next) => {
  try {
    const { id } = req.params;

    if (!mongoose.Types.ObjectId.isValid(id)) {
      return res.status(400).json({
        success: false,
        message: "Invalid library id",
      });
    }

    const item = await Library.findById(id);

    if (!item) {
      return res.status(404).json({
        success: false,
        message: "Library item not found",
      });
    }

    // ✅ Check user access
    const accessCheck = await checkUserCompanyAccess(req, item.companyId.toString());
    if (!accessCheck.allowed) {
      return res.status(403).json({
        success: false,
        message: accessCheck.message,
      });
    }

    if (!item.file || !item.file.fileName) {
      return res.status(404).json({
        success: false,
        message: "File not found in database",
      });
    }

    const filePath = path.join(__dirname, "../../", "uploads", "library", item.file.fileName);

    if (!fs.existsSync(filePath)) {
      return res.status(404).json({
        success: false,
        message: "File not found on server",
      });
    }

    // ✅ Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: item.companyId,
      action: "share",
      module: "library",
      entityType: "Library",
      entityId: item._id,
      description: `Shared file: ${item.title}`,
      ipAddress: req.ip,
      userAgent: req.get("user-agent"),
    });

    // ✅ IMPORTANT: inline = better for sharing (not forced download)
    res.setHeader("Content-Type", item.file.mimeType || "application/octet-stream");
    res.setHeader(
      "Content-Disposition",
      `inline; filename="${encodeURIComponent(item.file.originalName || item.title)}"`
    );

    // stream file
    const fileStream = fs.createReadStream(filePath);
    fileStream.pipe(res);

    fileStream.on("error", (error) => {
      console.error("File stream error:", error);
      return res.status(500).json({
        success: false,
        message: "Error streaming file",
      });
    });
  } catch (error) {
    next(error);
  }
};

/**
 * ✅ Upload library item (CREATE) - REAL FILE UPLOAD
 * This will read file from: req.file
 * and store URL automatically in MongoDB
 */
exports.uploadLibraryItem = async (req, res, next) => {
  try {
    const { title, description, category, tags, companyId } = req.body;

    // ✅ Validate companyId
    const companyValidation = await validateCompanyId(companyId);
    if (!companyValidation.valid) {
      return res.status(400).json({
        success: false,
        message: companyValidation.message,
      });
    }

    // ✅ Check user access
    const accessCheck = await checkUserCompanyAccess(req, companyId);
    if (!accessCheck.allowed) {
      return res.status(403).json({
        success: false,
        message: accessCheck.message,
      });
    }

    // ✅ Validate required fields
    if (!title) {
      return res.status(400).json({ success: false, message: "title is required" });
    }

    if (!category) {
      return res.status(400).json({ success: false, message: "category is required" });
    }

    // ✅ multer file required
    if (!req.file) {
      return res.status(400).json({
        success: false,
        message: "File is required (send as form-data key: file)",
      });
    }

    // ✅ tags parsing (supports string or JSON)
    let parsedTags = [];
    if (tags) {
      if (Array.isArray(tags)) {
        parsedTags = tags;
      } else {
        try {
          // if tags sent like '["tag1","tag2"]'
          parsedTags = JSON.parse(tags);
        } catch (e) {
          // if tags sent like "tag1,tag2"
          parsedTags = tags.split(",").map((t) => t.trim()).filter(Boolean);
        }
      }
    }

    // ✅ Create URL from uploaded file
    const baseUrl = `${req.protocol}://${req.get("host")}`;
    const fileUrl = `${baseUrl}/uploads/library/${req.file.filename}`;

    const item = await Library.create({
      companyId,
      title: title.trim(),
      description: description ? description.trim() : "",
      category: category.trim(),
      tags: parsedTags,
      file: {
        originalName: req.file.originalname,
        fileName: req.file.filename,
        url: fileUrl,
        mimeType: req.file.mimetype,
        size: req.file.size,
        extension: path.extname(req.file.originalname).replace(".", ""),
        documentType: getDocumentType(req.file.mimetype, path.extname(req.file.originalname).replace(".", "")),
      },
      status: "active",
      createdBy: req.user._id,
      updatedBy: req.user._id,
    });

    await ActivityLog.create({
      userId: req.user._id,
      companyId: item.companyId,
      action: "create",
      module: "library",
      entityType: "Library",
      entityId: item._id,
      description: `Uploaded file: ${item.title}`,
      ipAddress: req.ip,
      userAgent: req.get("user-agent"),
    });

    const populatedItem = await Library.findById(item._id)
      .populate("companyId", "name code")
      .populate("createdBy", "firstName lastName email");

    /*
    // ✅ Send email to assigned company users
    try {
      const assignedUsers = await User.find({ 
        companies: companyId,
        status: 'active'
      });

      if (assignedUsers.length > 0) {
        const companyName = populatedItem.companyId.name;
        const uploaderName = `${populatedItem.createdBy.firstName} ${populatedItem.createdBy.lastName}`;
        
        const emailPromises = assignedUsers.map(user => {
          return sendEmail({
            to: user.email,
            subject: `New File Added to Marcom Library: ${populatedItem.title}`,
            text: `Hi ${user.firstName},\n\nA new file "${populatedItem.title}" has been added to the Marcom Library for ${companyName} by ${uploaderName}.\n\nCategory: ${populatedItem.category}\n\nYou can view it in the library section of the dashboard.\n\nBest regards,\nArihant Industries Team`,
            html: `
              <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e0e0e0; border-radius: 8px;">
                <h2 style="color: #2c3e50;">New Library File Added</h2>
                <p>Hi ${user.firstName},</p>
                <p>A new file <strong>"${populatedItem.title}"</strong> has been added to the Marcom Library for <strong>${companyName}</strong>.</p>
                <div style="background-color: #f9f9f9; padding: 15px; border-radius: 5px; margin: 20px 0;">
                  <p style="margin: 5px 0;"><strong>Uploaded by:</strong> ${uploaderName}</p>
                  <p style="margin: 5px 0;"><strong>Category:</strong> ${populatedItem.category}</p>
                  <p style="margin: 5px 0;"><strong>Description:</strong> ${populatedItem.description || 'No description provided'}</p>
                </div>
                <p>You can view and download this file by logging into your dashboard.</p>
                <div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #eeeeee; font-size: 12px; color: #7f8c8d;">
                  <p>This is an automated notification from Arihant Industries CRM.</p>
                </div>
              </div>
            `
          });
        });

        // We don't want to block the response, but we should handle errors
        Promise.all(emailPromises).catch(err => {
          console.error("Failed to send some notification emails:", err);
        });
      }
    } catch (emailError) {
      console.error("Error in email notification process:", emailError);
      // Don't fail the upload if email fails
    }
    */

    return res.status(201).json({
      success: true,
      message: "Library item uploaded successfully",
      data: populatedItem,
    });
  } catch (error) {
    next(error);
  }
};

// ✅ Update library item
exports.updateLibraryItem = async (req, res, next) => {
  try {
    const { id } = req.params;
    const updates = req.body;

    const item = await Library.findById(id);

    if (!item) {
      return res.status(404).json({
        success: false,
        message: "Library item not found",
      });
    }

    const accessCheck = await checkUserCompanyAccess(
      req,
      item.companyId.toString()
    );
    if (!accessCheck.allowed) {
      return res.status(403).json({
        success: false,
        message: accessCheck.message,
      });
    }

    delete updates.companyId;
    delete updates.createdBy;

    // ✅ tags parsing for form-data (supports string or JSON)
    if (updates.tags) {
      if (!Array.isArray(updates.tags)) {
        try {
          updates.tags = JSON.parse(updates.tags);
        } catch (e) {
          updates.tags = updates.tags.split(",").map((t) => t.trim()).filter(Boolean);
        }
      }
    }

    if (req.file) {
      const baseUrl = `${req.protocol}://${req.get("host")}`;
      const fileUrl = `${baseUrl}/uploads/library/${req.file.filename}`;
      updates.file = {
        originalName: req.file.originalname,
        fileName: req.file.filename,
        url: fileUrl,
        mimeType: req.file.mimetype,
        size: req.file.size,
        extension: path.extname(req.file.originalname).replace(".", ""),
        documentType: getDocumentType(req.file.mimetype, path.extname(req.file.originalname).replace(".", "")),
      };
    } else {
      delete updates.file;
    }

    updates.updatedBy = req.user._id;

    const updatedItem = await Library.findByIdAndUpdate(id, updates, {
      new: true,
      runValidators: true,
    })
      .populate("companyId", "name code")
      .populate("createdBy", "firstName lastName email")
      .populate("updatedBy", "firstName lastName email");

    await ActivityLog.create({
      userId: req.user._id,
      companyId: item.companyId,
      action: "update",
      module: "library",
      entityType: "Library",
      entityId: item._id,
      description: `Updated library item: ${item.title}`,
      changes: updates,
      ipAddress: req.ip,
      userAgent: req.get("user-agent"),
    });

    return res.status(200).json({
      success: true,
      message: "Library item updated successfully",
      data: updatedItem,
    });
  } catch (error) {
    next(error);
  }
};

// ✅ Delete library item (Soft Delete)
exports.deleteLibraryItem = async (req, res, next) => {
  try {
    const { id } = req.params;

    const item = await Library.findById(id);

    if (!item) {
      return res.status(404).json({
        success: false,
        message: "Library item not found",
      });
    }

    const accessCheck = await checkUserCompanyAccess(
      req,
      item.companyId.toString()
    );
    if (!accessCheck.allowed) {
      return res.status(403).json({
        success: false,
        message: accessCheck.message,
      });
    }

    item.status = "deleted";
    item.updatedBy = req.user._id;
    await item.save();

    await ActivityLog.create({
      userId: req.user._id,
      companyId: item.companyId,
      action: "delete",
      module: "library",
      entityType: "Library",
      entityId: item._id,
      description: `Deleted library item: ${item.title}`,
      ipAddress: req.ip,
      userAgent: req.get("user-agent"),
    });

    return res.status(200).json({
      success: true,
      message: "Library item deleted successfully",
    });
  } catch (error) {
    next(error);
  }
};