import { existsSync, readFileSync, mkdirSync, unlinkSync } from 'node:fs';
import os__default, { homedir } from 'node:os';
import { c as createDefaultGateway } from './ccjk.D0g2ABGg.mjs';
import { CLOUD_ENDPOINTS } from '../chunks/constants.mjs';
import { writeFileAtomic } from '../chunks/fs-operations.mjs';
import { Buffer } from 'node:buffer';
import crypto from 'node:crypto';
import { j as join } from './ccjk.bQ7Dh1g4.mjs';

function validateBindRequest(request) {
  const errors = [];
  if (!request.code || typeof request.code !== "string") {
    errors.push("code is required and must be a string");
  } else if (request.code.length < 4) {
    errors.push("code must be at least 4 characters");
  }
  if (!request.deviceInfo || typeof request.deviceInfo !== "object") {
    errors.push("deviceInfo is required and must be an object");
  } else {
    if (!request.deviceInfo.name || typeof request.deviceInfo.name !== "string") {
      errors.push("deviceInfo.name is required and must be a string");
    }
    if (!request.deviceInfo.platform || typeof request.deviceInfo.platform !== "string") {
      errors.push("deviceInfo.platform is required and must be a string");
    }
  }
  return {
    valid: errors.length === 0,
    errors
  };
}
function validateNotifyRequest(request) {
  const errors = [];
  if (!request.title || typeof request.title !== "string") {
    errors.push("title is required and must be a string");
  } else if (request.title.length > 200) {
    errors.push("title must be 200 characters or less");
  }
  if (!request.body || typeof request.body !== "string") {
    errors.push("body is required and must be a string");
  } else if (request.body.length > 4e3) {
    errors.push("body must be 4000 characters or less");
  }
  if (request.type && !["info", "success", "warning", "error"].includes(request.type)) {
    errors.push("type must be one of: info, success, warning, error");
  }
  if (request.actions) {
    if (!Array.isArray(request.actions)) {
      errors.push("actions must be an array");
    } else {
      request.actions.forEach((action, index) => {
        if (!action.id || typeof action.id !== "string") {
          errors.push(`actions[${index}].id is required and must be a string`);
        }
        if (!action.label || typeof action.label !== "string") {
          errors.push(`actions[${index}].label is required and must be a string`);
        }
        if (!action.value || typeof action.value !== "string") {
          errors.push(`actions[${index}].value is required and must be a string`);
        }
      });
    }
  }
  return {
    valid: errors.length === 0,
    errors
  };
}
function validateBindResponse(response) {
  const errors = [];
  if (typeof response.success !== "boolean") {
    errors.push("success is required and must be a boolean");
  }
  if (response.success) {
    if (!response.data) {
      errors.push("data is required when success is true");
    } else {
      if (!response.data.deviceToken || typeof response.data.deviceToken !== "string") {
        errors.push("data.deviceToken is required and must be a string");
      }
      if (!response.data.deviceId || typeof response.data.deviceId !== "string") {
        errors.push("data.deviceId is required and must be a string");
      }
    }
  } else {
    if (!response.error || typeof response.error !== "string") {
      errors.push("error is required when success is false");
    }
  }
  return {
    valid: errors.length === 0,
    errors
  };
}
function validateNotifyResponse(response) {
  const errors = [];
  if (typeof response.success !== "boolean") {
    errors.push("success is required and must be a boolean");
  }
  if (response.success) {
    if (!response.data) {
      errors.push("data is required when success is true");
    } else {
      if (!response.data.notificationId || typeof response.data.notificationId !== "string") {
        errors.push("data.notificationId is required and must be a string");
      }
    }
  } else {
    if (!response.error || typeof response.error !== "string") {
      errors.push("error is required when success is false");
    }
  }
  return {
    valid: errors.length === 0,
    errors
  };
}
function validatePollResponse(response) {
  const errors = [];
  if (typeof response.success !== "boolean") {
    errors.push("success is required and must be a boolean");
  }
  if (response.success) {
    if (!response.data) {
      errors.push("data is required when success is true");
    } else if (response.data.reply !== null) {
      const reply = response.data.reply;
      if (!reply.content || typeof reply.content !== "string") {
        errors.push("data.reply.content is required and must be a string");
      }
      if (!reply.timestamp || typeof reply.timestamp !== "string") {
        errors.push("data.reply.timestamp is required and must be a string");
      }
    }
  } else {
    if (!response.error || typeof response.error !== "string") {
      errors.push("error is required when success is false");
    }
  }
  return {
    valid: errors.length === 0,
    errors
  };
}

const TOKEN_PREFIX = "ccjk_";
const TOKEN_LENGTH = 64;
const TOKEN_VERSION = 1;
function generateDeviceToken() {
  const randomBytes = crypto.randomBytes(TOKEN_LENGTH / 2);
  const randomHex = randomBytes.toString("hex");
  return `${TOKEN_PREFIX}${TOKEN_VERSION}${randomHex}`;
}
function isValidTokenFormat(token) {
  if (!token || typeof token !== "string") {
    return false;
  }
  if (!token.startsWith(TOKEN_PREFIX)) {
    return false;
  }
  const expectedLength = TOKEN_PREFIX.length + 1 + TOKEN_LENGTH;
  if (token.length !== expectedLength) {
    return false;
  }
  const version = token[TOKEN_PREFIX.length];
  if (!/^\d$/.test(version)) {
    return false;
  }
  const hexPart = token.slice(TOKEN_PREFIX.length + 1);
  if (!/^[a-f0-9]+$/i.test(hexPart)) {
    return false;
  }
  return true;
}
function getDeviceInfo() {
  return {
    name: os__default.hostname(),
    platform: os__default.platform(),
    osVersion: os__default.release(),
    arch: os__default.arch(),
    username: os__default.userInfo().username,
    machineId: generateMachineId()
  };
}
function generateMachineId() {
  const components = [
    os__default.hostname(),
    os__default.platform(),
    os__default.arch(),
    os__default.cpus()[0]?.model || "unknown",
    os__default.userInfo().username,
    // Add network interface MAC addresses for uniqueness
    ...Object.values(os__default.networkInterfaces()).flat().filter((iface) => iface && !iface.internal && iface.mac !== "00:00:00:00:00:00").map((iface) => iface?.mac).filter(Boolean).slice(0, 3)
    // Limit to first 3 MACs
  ];
  const combined = components.join("|");
  return crypto.createHash("sha256").update(combined).digest("hex").slice(0, 32);
}
function deriveEncryptionKey() {
  const machineId = generateMachineId();
  const salt = "ccjk-notification-token-v1";
  return crypto.pbkdf2Sync(machineId, salt, 1e5, 32, "sha256");
}
function encryptToken(token) {
  const key = deriveEncryptionKey();
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
  let encrypted = cipher.update(token, "utf8", "hex");
  encrypted += cipher.final("hex");
  const authTag = cipher.getAuthTag();
  return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted}`;
}
function decryptToken(encryptedToken) {
  try {
    const parts = encryptedToken.split(":");
    if (parts.length !== 3) {
      return null;
    }
    const [ivHex, authTagHex, encrypted] = parts;
    const key = deriveEncryptionKey();
    const iv = Buffer.from(ivHex, "hex");
    const authTag = Buffer.from(authTagHex, "hex");
    const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
    decipher.setAuthTag(authTag);
    let decrypted = decipher.update(encrypted, "hex", "utf8");
    decrypted += decipher.final("utf8");
    return decrypted;
  } catch {
    return null;
  }
}
function maskToken(token) {
  if (!token || token.length < 12) {
    return "***";
  }
  const prefix = token.slice(0, TOKEN_PREFIX.length + 1);
  const suffix = token.slice(-4);
  return `${prefix}***...***${suffix}`;
}

const CLOUD_API_BASE_URL = CLOUD_ENDPOINTS.MAIN.BASE_URL;
const POLL_TIMEOUT = 6e4;
const TOKEN_FILE_PATH = join(homedir(), ".ccjk", "cloud-token.json");
class CCJKCloudClient {
  baseUrl;
  deviceToken = null;
  deviceId = null;
  gateway = createDefaultGateway();
  /**
   * Create a new CCJKCloudClient instance
   *
   * @param baseUrl - Cloud API base URL (default: https://api.claudehome.cn)
   */
  constructor(baseUrl = CLOUD_API_BASE_URL) {
    this.baseUrl = baseUrl;
    this.loadToken();
  }
  // ==========================================================================
  // Token Management
  // ==========================================================================
  /**
   * Load token from storage file
   */
  loadToken() {
    try {
      if (existsSync(TOKEN_FILE_PATH)) {
        const data = readFileSync(TOKEN_FILE_PATH, "utf-8");
        const storage = JSON.parse(data);
        this.deviceToken = storage.deviceToken;
        this.deviceId = storage.deviceId || null;
      }
    } catch {
      this.deviceToken = null;
      this.deviceId = null;
    }
  }
  /**
   * Save token to storage file
   */
  saveToken(storage) {
    try {
      const dir = join(homedir(), ".ccjk");
      if (!existsSync(dir)) {
        mkdirSync(dir, { recursive: true });
      }
      writeFileAtomic(TOKEN_FILE_PATH, JSON.stringify(storage, null, 2));
    } catch (error) {
      throw new Error(`Failed to save token: ${error instanceof Error ? error.message : String(error)}`);
    }
  }
  /**
   * Check if device is bound
   */
  isBound() {
    return this.deviceToken !== null && this.deviceToken.length > 0;
  }
  /**
   * Get current device token
   */
  getDeviceToken() {
    return this.deviceToken;
  }
  /**
   * Get current device ID
   */
  getDeviceId() {
    return this.deviceId;
  }
  /**
   * Clear stored token (unbind device)
   */
  clearToken() {
    this.deviceToken = null;
    this.deviceId = null;
    try {
      if (existsSync(TOKEN_FILE_PATH)) {
        unlinkSync(TOKEN_FILE_PATH);
      }
    } catch {
    }
  }
  // ==========================================================================
  // Device Binding
  // ==========================================================================
  /**
   * Bind device using a binding code
   *
   * The binding code is obtained from the CCJK mobile app or web dashboard.
   * Once bound, the device can send and receive notifications.
   *
   * @param code - Binding code from mobile app
   * @param deviceInfo - Optional device information (auto-detected if not provided)
   * @returns Bind response with device token
   *
   * @example
   * ```typescript
   * const client = new CCJKCloudClient()
   * const result = await client.bind('ABC123')
   * if (result.success) {
   *   console.log('Device bound successfully!')
   * }
   * ```
   */
  async bind(code, deviceInfo) {
    const info = deviceInfo ? { ...getDeviceInfo(), ...deviceInfo } : getDeviceInfo();
    const requestPayload = {
      code,
      deviceInfo: info
    };
    const requestValidation = validateBindRequest(requestPayload);
    if (!requestValidation.valid) {
      return {
        success: false,
        error: `Invalid bind request: ${requestValidation.errors.join(", ")}`,
        code: "VALIDATION_ERROR"
      };
    }
    const response = await this.gateway.request("notifications.bind", {
      method: "POST",
      body: requestPayload,
      authToken: this.deviceToken || void 0
    });
    const responseValidation = validateBindResponse(response);
    if (!responseValidation.valid) {
      return {
        success: false,
        error: `Invalid bind response: ${responseValidation.errors.join(", ")}`,
        code: "RESPONSE_VALIDATION_ERROR"
      };
    }
    if (response.success && response.data) {
      this.deviceToken = response.data.deviceToken;
      this.deviceId = response.data.deviceId;
      this.gateway.setAuthToken(response.data.deviceToken);
      this.saveToken({
        deviceToken: response.data.deviceToken,
        deviceId: response.data.deviceId,
        bindingCode: code,
        createdAt: (/* @__PURE__ */ new Date()).toISOString(),
        deviceInfo: info
      });
      return {
        success: true,
        data: {
          deviceToken: response.data.deviceToken,
          deviceId: response.data.deviceId
        }
      };
    }
    return {
      success: false,
      error: response.error || "Failed to bind device",
      code: response.code
    };
  }
  // ==========================================================================
  // Notification Sending
  // ==========================================================================
  /**
   * Send a notification to the user
   *
   * @param options - Notification options
   * @returns Notification response
   *
   * @example
   * ```typescript
   * const client = new CCJKCloudClient()
   * await client.notify({
   *   title: 'Build Complete',
   *   body: 'Your project has been built successfully!',
   *   type: 'success'
   * })
   * ```
   */
  async notify(options) {
    if (!this.deviceToken) {
      return {
        success: false,
        error: 'Device not bound. Please run "ccjk notification bind <code>" first.',
        code: "NOT_BOUND"
      };
    }
    const requestPayload = {
      title: options.title,
      body: options.body,
      type: options.type || "info",
      taskId: options.taskId,
      metadata: options.metadata,
      actions: options.actions
    };
    const requestValidation = validateNotifyRequest(requestPayload);
    if (!requestValidation.valid) {
      return {
        success: false,
        error: `Invalid notify request: ${requestValidation.errors.join(", ")}`,
        code: "VALIDATION_ERROR"
      };
    }
    const response = await this.gateway.request("notifications.send", {
      method: "POST",
      body: requestPayload,
      authToken: this.deviceToken
    });
    const responseValidation = validateNotifyResponse(response);
    if (!responseValidation.valid) {
      return {
        success: false,
        error: `Invalid notify response: ${responseValidation.errors.join(", ")}`,
        code: "RESPONSE_VALIDATION_ERROR"
      };
    }
    if (response.success && response.data) {
      return {
        success: true,
        data: {
          notificationId: response.data.notificationId
        }
      };
    }
    return {
      success: false,
      error: response.error || "Failed to send notification",
      code: response.code
    };
  }
  // ==========================================================================
  // Reply Polling
  // ==========================================================================
  /**
   * Wait for a reply from the user
   *
   * Uses long-polling to wait for a user reply. The timeout parameter
   * controls how long to wait before returning null.
   *
   * @param timeout - Timeout in milliseconds (default: 30000)
   * @returns User reply or null if timeout
   *
   * @example
   * ```typescript
   * const client = new CCJKCloudClient()
   * const reply = await client.waitForReply(60000) // Wait up to 60 seconds
   * if (reply) {
   *   console.log('User replied:', reply.content)
   * }
   * ```
   */
  async waitForReply(timeout = POLL_TIMEOUT) {
    if (!this.deviceToken) {
      throw new Error('Device not bound. Please run "ccjk notification bind <code>" first.');
    }
    const response = await this.gateway.request("notifications.poll", {
      method: "GET",
      query: { timeout },
      authToken: this.deviceToken,
      timeout
    });
    const responseValidation = validatePollResponse(response);
    if (!responseValidation.valid) {
      throw new Error(`Invalid poll response: ${responseValidation.errors.join(", ")}`);
    }
    if (!response.success) {
      throw new Error(response.error || "Failed to poll for reply");
    }
    if (response.data?.reply) {
      return {
        content: response.data.reply.content,
        timestamp: new Date(response.data.reply.timestamp),
        notificationId: response.data.reply.notificationId,
        actionId: response.data.reply.actionId
      };
    }
    return null;
  }
  // ==========================================================================
  // Ask and Wait
  // ==========================================================================
  /**
   * Ask the user a question and wait for their reply
   *
   * This is a convenience method that combines notify() and waitForReply().
   * It sends a notification with the question and waits for the user to respond.
   *
   * @param question - Question to ask the user
   * @param options - Additional notification options
   * @param timeout - Timeout in milliseconds (default: 60000)
   * @returns User reply
   *
   * @example
   * ```typescript
   * const client = new CCJKCloudClient()
   * const reply = await client.ask('Deploy to production?', {
   *   actions: [
   *     { id: 'yes', label: 'Yes', value: 'yes' },
   *     { id: 'no', label: 'No', value: 'no' }
   *   ]
   * })
   * if (reply.actionId === 'yes') {
   *   // Proceed with deployment
   * }
   * ```
   */
  async ask(question, options, timeout = POLL_TIMEOUT) {
    const notifyResult = await this.notify({
      title: options?.title || "CCJK Question",
      body: question,
      type: "info",
      ...options
    });
    if (!notifyResult.success) {
      throw new Error(notifyResult.error || "Failed to send question");
    }
    const reply = await this.waitForReply(timeout);
    if (!reply) {
      throw new Error("No reply received within timeout");
    }
    return reply;
  }
  // ==========================================================================
  // Status Check
  // ==========================================================================
  /**
   * Get binding status and device information
   *
   * @returns Binding status information
   */
  async getStatus() {
    if (!this.deviceToken) {
      return { bound: false };
    }
    try {
      if (existsSync(TOKEN_FILE_PATH)) {
        const data = readFileSync(TOKEN_FILE_PATH, "utf-8");
        const storage = JSON.parse(data);
        return {
          bound: true,
          deviceId: storage.deviceId,
          deviceInfo: storage.deviceInfo,
          lastUsed: storage.lastUsedAt
        };
      }
    } catch {
    }
    return {
      bound: true,
      deviceId: this.deviceId || void 0
    };
  }
  // Note: HTTP requests now handled by CloudApiGateway
}
let cloudClientInstance = null;
function getCloudNotificationClient() {
  if (!cloudClientInstance) {
    cloudClientInstance = new CCJKCloudClient();
  }
  return cloudClientInstance;
}
async function bindDevice(code, deviceInfo) {
  const client = getCloudNotificationClient();
  return client.bind(code, deviceInfo);
}
async function sendNotification(options) {
  const client = getCloudNotificationClient();
  return client.notify(options);
}
function isDeviceBound() {
  const client = getCloudNotificationClient();
  return client.isBound();
}
async function getBindingStatus() {
  const client = getCloudNotificationClient();
  return client.getStatus();
}
function unbindDevice() {
  const client = getCloudNotificationClient();
  client.clearToken();
}

export { isValidTokenFormat as a, bindDevice as b, generateDeviceToken as c, decryptToken as d, encryptToken as e, getDeviceInfo as f, getBindingStatus as g, isDeviceBound as i, maskToken as m, sendNotification as s, unbindDevice as u };
