const CONFIG = {
  SPREADSHEET_ID: "1q4r08nBA_ClWv3ypPCQ6GVCfMVkQwSKzDSRiokkQQ8Q", // ID from mail_forwarding
  SHEET_NAME: "Form Responses 1",
  COL_FORWARD_TO_ADDRESS: 4, // 1-indexed (Column D from mail_forwarding)
  ADMIN_EMAIL: "info@haumdaucher.de",
  PROJECT_ID: "haumdaucher", // Used in the Identity Toolkit REST API
  DRY_RUN: false,
  SEND_EMAIL_ON_CREATION: false,
};

/**
 * Run this function from the Apps Script IDE after pushing code
 * to establish the required background triggers.
 */
function setup() {
  const ss = SpreadsheetApp.openById(CONFIG.SPREADSHEET_ID);

  // Clear old triggers
  const existingTriggers = ScriptApp.getProjectTriggers();
  for (const trigger of existingTriggers) {
    if (trigger.getHandlerFunction() === 'syncUsers') {
      ScriptApp.deleteTrigger(trigger);
    }
  }

  // Install triggers
  ScriptApp.newTrigger('syncUsers')
    .forSpreadsheet(ss)
    .onFormSubmit()
    .create();

  ScriptApp.newTrigger('syncUsers')
    .forSpreadsheet(ss)
    .onChange()
    .create();

  const triggers = ScriptApp.getProjectTriggers();
  console.log(`Setup complete. ${triggers.length} trigger(s) are now active for 'syncUsers'.`);
}

/**
 * Main Entry Point
 */
function syncUsers() {
  console.log(`Starting syncUsers... (DRY_RUN: ${CONFIG.DRY_RUN})`);

  try {
    const desiredEmails = getDesiredState();
    console.log(`Desired state: ${desiredEmails.length} valid email(s) found in sheet.`);

    const currentState = getCurrentState();
    console.log(`Current state: ${Object.keys(currentState).length} user(s) found in Firebase.`);

    const actions = reconcileUsers(desiredEmails, currentState);

    if (actions.length > 0) {
      console.log(`Found ${actions.length} action(s) to execute.`);
      sendAdminReport(actions);
    } else {
      console.log("States are synchronized. No actions required.");
    }

  } catch (err) {
    console.error("Error during syncUsers:", err);
    MailApp.sendEmail({
      to: CONFIG.ADMIN_EMAIL,
      subject: "Haumdaucher Firebase Sync Failed",
      body: `The Firebase User sync script failed with the following error:\n\n${err.toString()}`
    });
  }
}

/**
 * Extracts valid emails from the Google Sheet.
 */
function getDesiredState() {
  const ss = SpreadsheetApp.openById(CONFIG.SPREADSHEET_ID);
  const sheet = ss.getSheetByName(CONFIG.SHEET_NAME);
  const data = sheet.getDataRange().getValues();

  const emails = new Set();

  // Start from row 1 (skipping header row 0)
  for (let i = 1; i < data.length; i++) {
    const row = data[i];
    const email = row[CONFIG.COL_FORWARD_TO_ADDRESS - 1];

    if (email && typeof email === 'string' && email.trim() !== "") {
      const cleanEmail = email.trim().toLowerCase();
      emails.add(cleanEmail);
    }
  }

  return Array.from(emails);
}

/**
 * Fetches all users from Firebase Identity Platform.
 * Returns an object map: { "email@example.com": { localId: "...", disabled: false } }
 */
function getCurrentState() {
  const token = ScriptApp.getOAuthToken();
  const url = `https://identitytoolkit.googleapis.com/v1/projects/${CONFIG.PROJECT_ID}/accounts:query`;

  // We use query with an empty payload to list users.
  // Note: For very large datasets, pagination (nextPageToken) would be required.
  const payload = {
    returnUserInfo: true,
    maxResults: 1000 // Safely assuming < 1000 users as per requirements
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      "Authorization": "Bearer " + token
    },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  console.log("Calling Identity Toolkit accounts:query...");
  const response = UrlFetchApp.fetch(url, options);
  const json = JSON.parse(response.getContentText());

  if (response.getResponseCode() !== 200) {
    throw new Error(`Firebase API Error: ${response.getContentText()}`);
  }

  const userMap = {};
  if (json.userInfo) {
    json.userInfo.forEach(user => {
      if (user.email) {
        userMap[user.email.toLowerCase()] = {
          localId: user.localId,
          disabled: user.disabled || false
        };
      }
    });
  }
  return userMap;
}

/**
 * Evaluates differences and executes mutations against Firebase.
 */
function reconcileUsers(desiredEmails, currentState) {
  const token = ScriptApp.getOAuthToken();
  const executedActions = [];

  // Build a Set for O(1) lookup performance (avoids O(n²) with .includes())
  const desiredSet = new Set(desiredEmails);

  // 1. Check for Creations and Re-enables
  for (const email of desiredEmails) {
    const fbUser = currentState[email];

    if (!fbUser) {
      // Missing in Firebase -> CREATE
      console.log(`[ACTION: CREATE] User missing in Firebase: ${email}`);
      if (!CONFIG.DRY_RUN) {
        const password = generateSecurePassword();
        const success = createUserInFirebase(email, password, token);
        if (success) {
          executedActions.push(`Created user: ${email}`);
          if (CONFIG.SEND_EMAIL_ON_CREATION) {
            sendPasswordReset(email, token);
            executedActions.push(`Sent password reset email to: ${email}`);
          }
        } else {
          executedActions.push(`[ERROR] Failed to create user: ${email}`);
        }
      } else {
        executedActions.push(`[DRY RUN] Would create user: ${email}`);
      }
    } else if (fbUser.disabled) {
      // Exists but disabled -> RE-ENABLE
      console.log(`[ACTION: RE-ENABLE] User is disabled in Firebase: ${email}`);
      if (!CONFIG.DRY_RUN) {
        const success = updateUserStatus(fbUser.localId, false, token);
        if (success) {
          executedActions.push(`Re-enabled user: ${email}`);
        } else {
          executedActions.push(`[ERROR] Failed to re-enable user: ${email}`);
        }
      } else {
        executedActions.push(`[DRY RUN] Would re-enable user: ${email}`);
      }
    }
  }

  // 2. Check for Disablements
  for (const [email, fbUser] of Object.entries(currentState)) {
    if (!desiredSet.has(email) && !fbUser.disabled) {
      // Exists in Firebase, but NOT in sheet -> DISABLE (Soft Delete)
      console.log(`[ACTION: DISABLE] User not in sheet: ${email}`);
      if (!CONFIG.DRY_RUN) {
        const success = updateUserStatus(fbUser.localId, true, token);
        if (success) {
          executedActions.push(`Disabled user: ${email}`);
        } else {
          executedActions.push(`[ERROR] Failed to disable user: ${email}`);
        }
      } else {
        executedActions.push(`[DRY RUN] Would disable user: ${email}`);
      }
    }
  }

  return executedActions;
}

/**
 * Calls Identity Toolkit to create a user.
 */
function createUserInFirebase(email, password, token) {
  const url = `https://identitytoolkit.googleapis.com/v1/projects/${CONFIG.PROJECT_ID}/accounts`;

  const payload = {
    email: email,
    password: password,
    emailVerified: true // Pre-verified since it comes from our trusted sheet
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: { "Authorization": "Bearer " + token },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  const res = UrlFetchApp.fetch(url, options);
  if (res.getResponseCode() !== 200) {
    console.error(`Failed to create ${email}: ${res.getContentText()}`);
    return false;
  }
  return true;
}

/**
 * Calls Identity Toolkit to update user status (enable/disable).
 */
function updateUserStatus(localId, disabled, token) {
  const url = `https://identitytoolkit.googleapis.com/v1/projects/${CONFIG.PROJECT_ID}/accounts:update`;

  const payload = {
    localId: localId,
    disableUser: disabled
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: { "Authorization": "Bearer " + token },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  const res = UrlFetchApp.fetch(url, options);
  if (res.getResponseCode() !== 200) {
    console.error(`Failed to update ${localId}: ${res.getContentText()}`);
    return false;
  }
  return true;
}

/**
 * Calls Identity Toolkit to send a password reset email.
 */
function sendPasswordReset(email, token) {
  const url = `https://identitytoolkit.googleapis.com/v1/projects/${CONFIG.PROJECT_ID}/accounts:sendOobCode`;

  const payload = {
    requestType: "PASSWORD_RESET",
    email: email
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: { "Authorization": "Bearer " + token },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  const res = UrlFetchApp.fetch(url, options);
  if (res.getResponseCode() !== 200) {
    console.error(`Failed to send reset email to ${email}: ${res.getContentText()}`);
  }
}

/**
 * Generates a 24-character cryptographically secure random password.
 * Uses Utilities.getSecureRandomBytes() instead of Math.random() for security.
 */
function generateSecurePassword() {
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:,.<>?";
  const bytes = Utilities.getSecureRandomBytes(24);
  let pwd = "";
  for (let i = 0; i < 24; i++) {
    // Mask to avoid modulo bias: chars.length (88) fits safely in a byte (0-255)
    pwd += chars.charAt(bytes[i] % chars.length);
  }
  return pwd;
}

/**
 * Sends the final admin report.
 */
function sendAdminReport(actions) {
  const subject = `Firebase User Sync Report ${CONFIG.DRY_RUN ? '[DRY RUN]' : ''}`;
  const body = `The synchronization process has completed.\n\nActions taken:\n` +
    actions.map(a => `- ${a}`).join("\n");

  MailApp.sendEmail({
    to: CONFIG.ADMIN_EMAIL,
    subject: subject,
    body: body
  });
}
