const admin = require("firebase-admin");
const client = require("../../../graphql-client/graphql-client").client;
const {
  DELETE_SHOP,
  DELETE_VENDORS_BY_SHOP,
  GET_BODYSHOP,
  GET_ASSOCIATED_USERS,
  DELETE_ASSOCIATIONS_BY_SHOP,
  GET_USER_ASSOCIATIONS_COUNT,
  DELETE_USER,
  GET_VENDORS,
  GET_JOBS_BY_SHOP,
  DELETE_JOBLINES_BY_JOB_IDS,
  DELETE_JOBS_BY_IDS,
  DELETE_AUDIT_TRAIL_BY_SHOP
} = require("../partsManagement.queries");

/**
 * Deletes a Firebase user by UID.
 * @param {string} uid - The Firebase user ID
 * @returns {Promise<void>}
 */
const deleteFirebaseUser = async (uid) => {
  if (!uid) throw new Error("User UID is required");
  return admin.auth().deleteUser(uid);
};

/**
 * Deletes all vendors associated with a shop.
 * @param {string} shopId - The shop ID
 * @returns {Promise<void>}
 */
const deleteVendorsByShop = async (shopId) => {
  if (!shopId) throw new Error("Shop ID is required");
  await client.request(DELETE_VENDORS_BY_SHOP, { shopId });
};

/**
 * Deletes a bodyshop from the database.
 * @param {string} shopId - The shop ID
 * @returns {Promise<void>}
 */
const deleteBodyshop = async (shopId) => {
  if (!shopId) throw new Error("Shop ID is required");
  await client.request(DELETE_SHOP, { id: shopId });
};

/**
 * Fetch job ids for a given shop
 * @param {string} shopId - The shop ID
 * @returns {Promise<string[]>}
 */
const getJobIdsForShop = async (shopId) => {
  if (!shopId) throw new Error("Shop ID is required");
  const resp = await client.request(GET_JOBS_BY_SHOP, { shopId });
  return resp.jobs?.map((j) => j.id) || [];
};

/**
 * Delete joblines for the given job ids
 * @param {string[]} jobIds - Array of job IDs
 * @returns {Promise<number>} affected rows
 */
const deleteJoblinesForJobs = async (jobIds) => {
  if (!jobIds?.length) return 0;
  const resp = await client.request(DELETE_JOBLINES_BY_JOB_IDS, { jobIds });
  return resp.delete_joblines?.affected_rows || 0;
};

/**
 * Delete jobs for the given job ids
 * @param {string[]} jobIds - Array of job IDs
 * @returns {Promise<number>} affected rows
 */
const deleteJobsByIds = async (jobIds) => {
  if (!jobIds?.length) return 0;
  const resp = await client.request(DELETE_JOBS_BY_IDS, { jobIds });
  return resp.delete_jobs?.affected_rows || 0;
};

/**
 * Handles deprovisioning a shop for parts management.
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 * @returns {Promise<*>}
 */
const partsManagementDeprovisioning = async (req, res) => {
  const { logger } = req;
  const { shopId } = req.body;

  if (process.env.NODE_ENV === "production" || process.env.HOSTNAME?.endsWith("compute.internal")) {
    return res.status(403).json({ error: "Deprovisioning not allowed in production environment." });
  }

  try {
    if (!shopId) {
      throw { status: 400, message: "shopId is required." };
    }

    // Fetch bodyshop and check external_shop_id
    const shopResp = await client.request(GET_BODYSHOP, { id: shopId });
    const shop = shopResp.bodyshops_by_pk;
    if (!shop) {
      throw { status: 404, message: `Bodyshop with id ${shopId} not found.` };
    }
    if (!shop.external_shop_id) {
      throw { status: 400, message: "Cannot delete bodyshop without external_shop_id." };
    }

    logger.log("admin-delete-shop", "debug", null, null, {
      shopId,
      shopname: shop.shopname,
      ioadmin: true
    });

    // Get vendors
    const vendorsResp = await client.request(GET_VENDORS, { shopId });
    const deletedVendors = vendorsResp.vendors?.map((v) => v.name) || [];

    // Get associated users
    const assocResp = await client.request(GET_ASSOCIATED_USERS, { shopId });
    const associatedUsers =
      assocResp.associations?.map((assoc) => ({
        authId: assoc.user?.authid,
        email: assoc.user?.email
      })) || [];

    // Delete associations for the shop
    const assocDeleteResp = await client.request(DELETE_ASSOCIATIONS_BY_SHOP, { shopId });
    const associationsDeleted = assocDeleteResp.delete_associations?.affected_rows || 0;

    // Delete users with no remaining associations
    const deletedUsers = [];
    for (const user of associatedUsers) {
      if (!user.email || !user.authId) continue;
      try {
        const countResp = await client.request(GET_USER_ASSOCIATIONS_COUNT, { userEmail: user.email });
        const assocCount = countResp.associations_aggregate?.aggregate?.count || 0;
        if (assocCount === 0) {
          await client.request(DELETE_USER, { email: user.email });
          await deleteFirebaseUser(user.authId);
          deletedUsers.push(user.email);
        }
      } catch (userError) {
        logger.log("admin-delete-user-error", "warn", null, null, {
          email: user.email,
          error: userError.message || userError
        });
      }
    }

    // Delete jobs and joblines
    const jobIds = await getJobIdsForShop(shopId);
    const joblinesDeleted = await deleteJoblinesForJobs(jobIds);
    const jobsDeleted = await deleteJobsByIds(jobIds);

    // Delete audit trail
    const auditResp = await client.request(DELETE_AUDIT_TRAIL_BY_SHOP, { shopId });
    const auditDeleted = auditResp.delete_audit_trail?.affected_rows || 0;

    // Delete vendors and shop
    await deleteVendorsByShop(shopId);
    await deleteBodyshop(shopId);

    // Summary log
    logger.log("admin-delete-shop-summary", "info", null, null, {
      shopId,
      shopname: shop.shopname,
      associationsDeleted,
      deletedUsers,
      deletedVendors,
      joblinesDeleted,
      jobsDeleted,
      auditDeleted
    });

    return res.status(200).json({
      message: `Bodyshop ${shopId} and associated resources deleted successfully.`,
      deletedShop: { id: shopId, name: shop.shopname },
      deletedAssociationsCount: associationsDeleted,
      deletedUsers,
      deletedVendors,
      deletedJoblinesCount: joblinesDeleted,
      deletedJobsCount: jobsDeleted,
      deletedAuditTrailCount: auditDeleted
    });
  } catch (err) {
    logger.log("admin-delete-shop-error", "error", null, null, {
      message: err.message,
      detail: err.detail || err.stack || err
    });
    return res.status(err.status || 500).json({ error: err.message || "Internal server error" });
  }
};

module.exports = partsManagementDeprovisioning;
