
import { Op } from "sequelize";
import { LeadManagement } from "../models/index.js";
import sequelize from "../config/db.js";

const formatPhone = (raw) => {
  const digits = raw.replace(/\D/g, "").slice(0, 10);
  if (digits.length !== 10) return null;
  return `+91 ${digits.slice(0, 5)} ${digits.slice(5)}`;
};

const extractValidationErrors = (err) => {

  const errors = {};
  if (err.errors) {
    err.errors.forEach((e) => {
      errors[e.path] = e.message;
    });
  }
  return errors;
};

export const getAllLeads = async (req, res) => {
  try {
    const {
      status,
      page = 1,
      limit = 5,
      source,
      sortBy = "date",
      order = "DESC",
    } = req.query;

   
    const where = {};
    if (status && status !== "All") where.status = status;
    if (source) where.source = { [Op.like]: `%${source}%` };

    const offset = (Number(page) - 1) * Number(limit);


    const allowedSortColumns = ["date", "name", "status", "source", "createdAt"];
    const sortColumn = allowedSortColumns.includes(sortBy) ? sortBy : "date";
    const sortDirection = order.toUpperCase() === "ASC" ? "ASC" : "DESC";

    const { count, rows: leads } = await LeadManagement.findAndCountAll({
      where,
      order: [[sortColumn, sortDirection]],
      limit: Number(limit),
      offset,
    });


    const statusCounts = await LeadManagement.findAll({
      attributes: [
        "status",
        [sequelize.fn("COUNT", sequelize.col("status")), "count"],
      ],
      group: ["status"],
      raw: true,
    });

    const stats = { total: 0, new: 0, contacted: 0, qualified: 0, disqualified: 0 };
    statusCounts.forEach(({ status: s, count: c }) => {
      stats.total += Number(c);
      if (s === "New") stats.new = Number(c);
      if (s === "Contacted") stats.contacted = Number(c);
      if (s === "Qualified") stats.qualified = Number(c);
      if (s === "Disqualified") stats.disqualified = Number(c);
    });

    res.status(200).json({
      success: true,
      data: leads,
      pagination: {
        total: count,
        page: Number(page),
        limit: Number(limit),
        totalPages: Math.ceil(count / Number(limit)),
      },
      stats: {
        ...stats,
        filtered: count,
        activeFilter: status || "All",
      },
    });
  } catch (err) {
    res.status(500).json({ success: false, message: "Server error", error: err.message });
  }
};


export const exportLeads = async (req, res) => {
  try {
    const { status } = req.query;
    const where = {};
    if (status && status !== "All") where.status = status;

    const leads = await LeadManagement.findAll({ where, order: [["date", "DESC"]] });

    const statusCounts = { New: 0, Contacted: 0, Qualified: 0, Disqualified: 0 };
    leads.forEach((l) => { statusCounts[l.status]++; });

    res.status(200).json({
      success: true,
      total: leads.length,
      generatedOn: new Date().toISOString(),
      statusCounts,
      data: leads,
    });
  } catch (err) {
    res.status(500).json({ success: false, message: "Server error", error: err.message });
  }
};


export const getLeadById = async (req, res) => {
  try {
    const { id } = req.params;


    const lead = /^L-\d+$/.test(id)
      ? await LeadManagement.findOne({ where: { leadId: id } })
      : await LeadManagement.findByPk(id);

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

    res.status(200).json({ success: true, data: lead });
  } catch (err) {
    res.status(500).json({ success: false, message: "Server error", error: err.message });
  }
};

export const createLead = async (req, res) => {
  try {
    const { name, email, phone, status, date, source, text_area } = req.body;

    if (name && /\d/.test(name)) {
      return res.status(400).json({
        success: false,
        message: "Validation failed",
        errors: { name: "Name must not contain numbers" },
      });
    }

    if (!phone || /\D/.test(phone.trim())) {
      return res.status(400).json({
        success: false,
        message: "Validation failed",
        errors: { phone: "Phone must contain digits only" },
      });
    }

    const formattedPhone = formatPhone(phone);
    if (!formattedPhone) {
      return res.status(400).json({
        success: false,
        message: "Validation failed",
        errors: { phone: "Phone must be exactly 10 digits" },
      });
    }

    const existing = await LeadManagement.findOne({
      where: {
        [Op.or]: [{ phone: formattedPhone }, { email }],
      },
    });

    if (existing) {
      const errors = {};
      if (existing.phone === formattedPhone) errors.phone = "Phone number already exists";
      if (existing.email === email) errors.email = "Email already exists";
      return res.status(400).json({ success: false, message: "Validation failed", errors });
    }

    const lastLead = await LeadManagement.findOne({ order: [["id", "DESC"]] });
    const nextNumber = lastLead
      ? parseInt(lastLead.leadId.replace("L-", ""), 10) + 1
      : 1;
    const leadId = `L-${nextNumber}`;

    const lead = await LeadManagement.create({
      leadId,
      name,
      email,
      phone: formattedPhone,
      status: status || "New",
      date: date || new Date().toISOString().split("T")[0],
      source,
      text_area,
    });

    res.status(201).json({ success: true, data: lead });
  } catch (err) {
    if (err.name === "SequelizeValidationError" || err.name === "SequelizeUniqueConstraintError") {
      return res.status(400).json({
        success: false,
        message: "Validation failed",
        errors: extractValidationErrors(err),
      });
    }
    res.status(500).json({ success: false, message: "Server error", error: err.message });
  }
};


export const updateLead = async (req, res) => {
  try {
    const { name, email, phone, status, date, source, text_area } = req.body;
    const { id } = req.params;

    if (name && /\d/.test(name)) {
      return res.status(400).json({
        success: false,
        message: "Validation failed",
        errors: { name: "Name must not contain numbers" },
      });
    }


    if (phone && /\D/.test(phone.trim())) {
      return res.status(400).json({
        success: false,
        message: "Validation failed",
        errors: { phone: "Phone must contain digits only" },
      });
    }

    let formattedPhone;
    if (phone) {
      formattedPhone = formatPhone(phone);
      if (!formattedPhone) {
        return res.status(400).json({
          success: false,
          message: "Validation failed",
          errors: { phone: "Phone must be exactly 10 digits" },
        });
      }
    }


    const where = /^L-\d+$/.test(id) ? { leadId: id } : { id };
    const existingLead = /^L-\d+$/.test(id)
      ? await LeadManagement.findOne({ where: { leadId: id } })
      : await LeadManagement.findByPk(id);

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


    const alreadySame = {};
    if (name && name === existingLead.name) alreadySame.name = name;
    if (email && email === existingLead.email) alreadySame.email = email;
    if (formattedPhone && formattedPhone === existingLead.phone) alreadySame.phone = formattedPhone;
    if (status && status === existingLead.status) alreadySame.status = status;
    if (date && date === existingLead.date) alreadySame.date = date;
    if (source && source === existingLead.source) alreadySame.source = source;
    if (text_area && text_area === existingLead.text_area) alreadySame.text_area = text_area;
    if (Object.keys(alreadySame).length === Object.keys(req.body).length) {
      return res.status(400).json({
        success: false,
        message: "Already up to date",
        alreadySame,
      });
    }

    const updatePayload = {
      ...(name && { name }),
      ...(email && { email }),
      ...(formattedPhone && { phone: formattedPhone }),
      ...(status && { status }),
      ...(date && { date }),
      ...(source && { source }),
      ...(text_area && { text_area }),
    };

    const [rowsUpdated] = await LeadManagement.update(updatePayload, { where, validate: true });

    if (rowsUpdated === 0) {
      return res.status(404).json({ success: false, message: "Lead not found" });
    }

    const updated = /^L-\d+$/.test(id)
      ? await LeadManagement.findOne({ where: { leadId: id } })
      : await LeadManagement.findByPk(id);

    res.status(200).json({ success: true, data: updated });
  } catch (err) {
    if (err.name === "SequelizeValidationError") {
      return res.status(400).json({
        success: false,
        message: "Validation failed",
        errors: extractValidationErrors(err),
      });
    }
    res.status(500).json({ success: false, message: "Server error", error: err.message });
  }
};


export const updateLeadStatus = async (req, res) => {
  try {
    const { status, ...otherFields } = req.body; 
    const { id } = req.params;
    const validStatuses = ["New", "Contacted", "Qualified", "Disqualified"];


    if (Object.keys(otherFields).length > 0) {
      return res.status(400).json({
        success: false,
        message: "Only status can be updated here",
        rejectedFields: Object.keys(otherFields),
      });
    }


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


    if (!validStatuses.includes(status)) {
      return res.status(400).json({
        success: false,
        message: `Status must be one of: ${validStatuses.join(", ")}`,
      });
    }


    const existingLead = /^L-\d+$/.test(id)
      ? await LeadManagement.findOne({ where: { leadId: id } })
      : await LeadManagement.findByPk(id);

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


    if (existingLead.status === status) {
      return res.status(400).json({
        success: false,
        message: `Status is already ${status}`,
      });
    }

    const previousStatus = existingLead.status;

    const where = /^L-\d+$/.test(id) ? { leadId: id } : { id };
    await LeadManagement.update({ status }, { where });

    const updated = /^L-\d+$/.test(id)
      ? await LeadManagement.findOne({ where: { leadId: id } })
      : await LeadManagement.findByPk(id);

    res.status(200).json({
      success: true,
      message: `Status updated from ${previousStatus} to ${status}`,
      data: updated,
    });
  } catch (err) {
    res.status(500).json({ success: false, message: "Server error", error: err.message });
  }
};


export const deleteLead = async (req, res) => {
  try {
    const { id } = req.params;
    const where = /^L-\d+$/.test(id) ? { leadId: id } : { id };

    const lead = /^L-\d+$/.test(id)
      ? await LeadManagement.findOne({ where: { leadId: id } })
      : await LeadManagement.findByPk(id);

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

    await LeadManagement.destroy({ where });
    res.status(200).json({ success: true, message: "Lead deleted successfully", data: lead });
  } catch (err) {
    res.status(500).json({ success: false, message: "Server error", error: err.message });
  }
};