import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { existsSync, readFileSync } from "fs";
import { join } from "path";
import { homedir } from "os";
import { config as loadDotenv } from "dotenv";
import { writeFileSecure, ensureSecureDir } from "./secure-fs.js";
import { SMSConfigSchema, parseConfigSafe } from "./schemas.js";
const CONFIG_PATH = join(homedir(), ".stackmemory", "sms-notify.json");
const DEFAULT_CONFIG = {
  enabled: false,
  channel: "whatsapp",
  // WhatsApp is cheaper for conversations
  notifyOn: {
    taskComplete: true,
    reviewReady: true,
    error: true,
    custom: true
  },
  quietHours: {
    enabled: false,
    start: "22:00",
    end: "08:00"
  },
  responseTimeout: 300,
  // 5 minutes
  pendingPrompts: []
};
function loadSMSConfig() {
  loadDotenv({ path: join(process.cwd(), ".env") });
  loadDotenv({ path: join(process.cwd(), ".env.local") });
  loadDotenv({ path: join(homedir(), ".env") });
  loadDotenv({ path: join(homedir(), ".stackmemory", ".env") });
  try {
    if (existsSync(CONFIG_PATH)) {
      const data = readFileSync(CONFIG_PATH, "utf8");
      const parsed = JSON.parse(data);
      const validated = parseConfigSafe(
        SMSConfigSchema,
        { ...DEFAULT_CONFIG, ...parsed },
        DEFAULT_CONFIG,
        "sms-notify"
      );
      applyEnvVars(validated);
      return validated;
    }
  } catch {
  }
  const config = { ...DEFAULT_CONFIG };
  applyEnvVars(config);
  return config;
}
function getMissingConfig() {
  const config = loadSMSConfig();
  const missing = [];
  const configured = [];
  if (config.accountSid) {
    configured.push("TWILIO_ACCOUNT_SID");
  } else {
    missing.push("TWILIO_ACCOUNT_SID");
  }
  if (config.authToken) {
    configured.push("TWILIO_AUTH_TOKEN");
  } else {
    missing.push("TWILIO_AUTH_TOKEN");
  }
  const channel = config.channel || "whatsapp";
  if (channel === "whatsapp") {
    const from = config.whatsappFromNumber || config.fromNumber;
    const to = config.whatsappToNumber || config.toNumber;
    if (from) {
      configured.push("TWILIO_WHATSAPP_FROM");
    } else {
      missing.push("TWILIO_WHATSAPP_FROM");
    }
    if (to) {
      configured.push("TWILIO_WHATSAPP_TO");
    } else {
      missing.push("TWILIO_WHATSAPP_TO");
    }
  } else {
    const from = config.smsFromNumber || config.fromNumber;
    const to = config.smsToNumber || config.toNumber;
    if (from) {
      configured.push("TWILIO_SMS_FROM");
    } else {
      missing.push("TWILIO_SMS_FROM");
    }
    if (to) {
      configured.push("TWILIO_SMS_TO");
    } else {
      missing.push("TWILIO_SMS_TO");
    }
  }
  return {
    missing,
    configured,
    ready: missing.length === 0
  };
}
function applyEnvVars(config) {
  if (process.env["TWILIO_ACCOUNT_SID"]) {
    config.accountSid = process.env["TWILIO_ACCOUNT_SID"];
  }
  if (process.env["TWILIO_AUTH_TOKEN"]) {
    config.authToken = process.env["TWILIO_AUTH_TOKEN"];
  }
  if (process.env["TWILIO_SMS_FROM"] || process.env["TWILIO_FROM_NUMBER"]) {
    config.smsFromNumber = process.env["TWILIO_SMS_FROM"] || process.env["TWILIO_FROM_NUMBER"];
  }
  if (process.env["TWILIO_SMS_TO"] || process.env["TWILIO_TO_NUMBER"]) {
    config.smsToNumber = process.env["TWILIO_SMS_TO"] || process.env["TWILIO_TO_NUMBER"];
  }
  if (process.env["TWILIO_WHATSAPP_FROM"]) {
    config.whatsappFromNumber = process.env["TWILIO_WHATSAPP_FROM"];
  }
  if (process.env["TWILIO_WHATSAPP_TO"]) {
    config.whatsappToNumber = process.env["TWILIO_WHATSAPP_TO"];
  }
  if (process.env["TWILIO_FROM_NUMBER"]) {
    config.fromNumber = process.env["TWILIO_FROM_NUMBER"];
  }
  if (process.env["TWILIO_TO_NUMBER"]) {
    config.toNumber = process.env["TWILIO_TO_NUMBER"];
  }
  if (process.env["TWILIO_CHANNEL"]) {
    config.channel = process.env["TWILIO_CHANNEL"];
  }
}
function saveSMSConfig(config) {
  try {
    ensureSecureDir(join(homedir(), ".stackmemory"));
    const safeConfig = { ...config };
    delete safeConfig.accountSid;
    delete safeConfig.authToken;
    writeFileSecure(CONFIG_PATH, JSON.stringify(safeConfig, null, 2));
  } catch {
  }
}
function isQuietHours(config) {
  if (!config.quietHours?.enabled) return false;
  const now = /* @__PURE__ */ new Date();
  const currentTime = now.getHours() * 60 + now.getMinutes();
  const [startH, startM] = config.quietHours.start.split(":").map(Number);
  const [endH, endM] = config.quietHours.end.split(":").map(Number);
  const startTime = startH * 60 + startM;
  const endTime = endH * 60 + endM;
  if (startTime > endTime) {
    return currentTime >= startTime || currentTime < endTime;
  }
  return currentTime >= startTime && currentTime < endTime;
}
function generatePromptId() {
  return Math.random().toString(36).substring(2, 10);
}
function formatPromptMessage(payload) {
  let message = `${payload.title}

${payload.message}`;
  if (payload.prompt) {
    message += "\n\n";
    if (payload.prompt.question) {
      message += `${payload.prompt.question}
`;
    }
    if (payload.prompt.type === "yesno") {
      message += "Reply Y for Yes, N for No";
    } else if (payload.prompt.type === "options" && payload.prompt.options) {
      payload.prompt.options.forEach((opt) => {
        message += `${opt.key}. ${opt.label}
`;
      });
      message += "\nReply with number to select";
    } else if (payload.prompt.type === "freeform") {
      message += "Reply with your response";
    }
  }
  return message;
}
function getChannelNumbers(config) {
  const channel = config.channel || "whatsapp";
  if (channel === "whatsapp") {
    const from2 = config.whatsappFromNumber || config.fromNumber;
    const to2 = config.whatsappToNumber || config.toNumber;
    if (from2 && to2) {
      return {
        from: from2.startsWith("whatsapp:") ? from2 : `whatsapp:${from2}`,
        to: to2.startsWith("whatsapp:") ? to2 : `whatsapp:${to2}`,
        channel: "whatsapp"
      };
    }
  }
  const from = config.smsFromNumber || config.fromNumber;
  const to = config.smsToNumber || config.toNumber;
  if (from && to) {
    return { from, to, channel: "sms" };
  }
  return null;
}
async function sendNotification(payload, channelOverride) {
  const config = loadSMSConfig();
  if (!config.enabled) {
    return { success: false, error: "Notifications disabled" };
  }
  const typeMap = {
    task_complete: "taskComplete",
    review_ready: "reviewReady",
    error: "error",
    custom: "custom"
  };
  if (!config.notifyOn[typeMap[payload.type]]) {
    return {
      success: false,
      error: `Notifications for ${payload.type} disabled`
    };
  }
  if (isQuietHours(config)) {
    return { success: false, error: "Quiet hours active" };
  }
  if (!config.accountSid || !config.authToken) {
    return {
      success: false,
      error: "Missing Twilio credentials. Set TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN"
    };
  }
  const originalChannel = config.channel;
  if (channelOverride) {
    config.channel = channelOverride;
  }
  const numbers = getChannelNumbers(config);
  config.channel = originalChannel;
  if (!numbers) {
    return {
      success: false,
      error: config.channel === "whatsapp" ? "Missing WhatsApp numbers. Set TWILIO_WHATSAPP_FROM and TWILIO_WHATSAPP_TO" : "Missing SMS numbers. Set TWILIO_SMS_FROM and TWILIO_SMS_TO"
    };
  }
  const message = formatPromptMessage(payload);
  let promptId;
  if (payload.prompt) {
    promptId = generatePromptId();
    const expiresAt = new Date(
      Date.now() + config.responseTimeout * 1e3
    ).toISOString();
    const pendingPrompt = {
      id: promptId,
      timestamp: (/* @__PURE__ */ new Date()).toISOString(),
      message: payload.message,
      options: payload.prompt.options || [],
      type: payload.prompt.type,
      expiresAt
    };
    config.pendingPrompts.push(pendingPrompt);
    saveSMSConfig(config);
  }
  try {
    const twilioUrl = `https://api.twilio.com/2010-04-01/Accounts/${config.accountSid}/Messages.json`;
    const response = await fetch(twilioUrl, {
      method: "POST",
      headers: {
        Authorization: "Basic " + Buffer.from(`${config.accountSid}:${config.authToken}`).toString(
          "base64"
        ),
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: new URLSearchParams({
        From: numbers.from,
        To: numbers.to,
        Body: message
      })
    });
    if (!response.ok) {
      const errorData = await response.text();
      return {
        success: false,
        channel: numbers.channel,
        error: `Twilio error: ${errorData}`
      };
    }
    return { success: true, promptId, channel: numbers.channel };
  } catch (err) {
    return {
      success: false,
      channel: numbers.channel,
      error: `Failed to send ${numbers.channel}: ${err instanceof Error ? err.message : String(err)}`
    };
  }
}
async function sendSMSNotification(payload) {
  return sendNotification(payload);
}
function processIncomingResponse(from, body) {
  const config = loadSMSConfig();
  const response = body.trim().toLowerCase();
  const now = /* @__PURE__ */ new Date();
  const validPrompts = config.pendingPrompts.filter(
    (p) => new Date(p.expiresAt) > now
  );
  if (validPrompts.length === 0) {
    return { matched: false };
  }
  const prompt = validPrompts[validPrompts.length - 1];
  let matchedOption;
  if (prompt.type === "yesno") {
    if (response === "y" || response === "yes") {
      matchedOption = { key: "y", label: "Yes" };
    } else if (response === "n" || response === "no") {
      matchedOption = { key: "n", label: "No" };
    }
  } else if (prompt.type === "options") {
    matchedOption = prompt.options.find(
      (opt) => opt.key.toLowerCase() === response
    );
  } else if (prompt.type === "freeform") {
    matchedOption = { key: response, label: response };
  }
  config.pendingPrompts = config.pendingPrompts.filter(
    (p) => p.id !== prompt.id
  );
  saveSMSConfig(config);
  if (matchedOption) {
    return {
      matched: true,
      prompt,
      response: matchedOption.key,
      action: matchedOption.action
    };
  }
  return { matched: false, prompt };
}
function getSessionId() {
  return process.env["CLAUDE_INSTANCE_ID"] || process.env["STACKMEMORY_SESSION_ID"] || Math.random().toString(36).substring(2, 8);
}
async function notifyReviewReady(title, description, options) {
  const sessionId = getSessionId();
  let finalOptions = options || [];
  if (finalOptions.length < 2) {
    const defaults = [
      { label: "Approve", action: 'echo "Approved"' },
      { label: "Request changes", action: 'echo "Changes requested"' }
    ];
    finalOptions = [...finalOptions, ...defaults].slice(
      0,
      Math.max(2, finalOptions.length)
    );
  }
  const payload = {
    type: "review_ready",
    title: `[Claude ${sessionId}] Review Ready: ${title}`,
    message: description,
    prompt: {
      type: "options",
      options: finalOptions.map((opt, i) => ({
        key: String(i + 1),
        label: opt.label,
        action: opt.action
      })),
      question: "What would you like to do?"
    }
  };
  return sendSMSNotification(payload);
}
async function notifyWithYesNo(title, question, yesAction, noAction) {
  const sessionId = getSessionId();
  return sendSMSNotification({
    type: "custom",
    title: `[Claude ${sessionId}] ${title}`,
    message: question,
    prompt: {
      type: "yesno",
      options: [
        { key: "y", label: "Yes", action: yesAction },
        { key: "n", label: "No", action: noAction }
      ]
    }
  });
}
async function notifyTaskComplete(taskName, summary) {
  const sessionId = getSessionId();
  return sendSMSNotification({
    type: "task_complete",
    title: `[Claude ${sessionId}] Task Complete: ${taskName}`,
    message: summary,
    prompt: {
      type: "options",
      options: [
        { key: "1", label: "Start next task", action: "claude-sm" },
        { key: "2", label: "View details", action: "stackmemory status" }
      ]
    }
  });
}
async function notifyError(error, context) {
  const sessionId = getSessionId();
  return sendSMSNotification({
    type: "error",
    title: `[Claude ${sessionId}] Error Alert`,
    message: context ? `${error}

Context: ${context}` : error,
    prompt: {
      type: "options",
      options: [
        { key: "1", label: "Retry", action: "claude-sm" },
        {
          key: "2",
          label: "View logs",
          action: "tail -50 ~/.claude/logs/*.log"
        }
      ]
    }
  });
}
function cleanupExpiredPrompts() {
  const config = loadSMSConfig();
  const now = /* @__PURE__ */ new Date();
  const before = config.pendingPrompts.length;
  config.pendingPrompts = config.pendingPrompts.filter(
    (p) => new Date(p.expiresAt) > now
  );
  const removed = before - config.pendingPrompts.length;
  if (removed > 0) {
    saveSMSConfig(config);
  }
  return removed;
}
export {
  cleanupExpiredPrompts,
  getMissingConfig,
  loadSMSConfig,
  notifyError,
  notifyReviewReady,
  notifyTaskComplete,
  notifyWithYesNo,
  processIncomingResponse,
  saveSMSConfig,
  sendNotification,
  sendSMSNotification
};
//# sourceMappingURL=sms-notify.js.map
