import {
  transformCreateInput,
  transformProfile,
  transformSaveInput,
  transformSession,
  transformStateResponse
} from "./chunk-2AMEQAO2.js";
import {
  MorphAuthenticationError,
  MorphValidationError,
  parseAPIError
} from "./chunk-2VERUKO2.js";
import {
  fetchWithRetry
} from "./chunk-E6BQJL5D.js";

// tools/browser/profiles/core.ts
var DEFAULT_API_URL = process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com";
var ProfilesClient = class {
  config;
  constructor(config) {
    this.config = config;
  }
  /**
    * Create a new browser profile and immediately start a live session.
    *
    * @param input - Profile creation parameters
    * @returns Profile setup handle with live URL + save()
    * @throws {MorphValidationError} If input validation fails
    * @throws {MorphProfileLimitError} If profile limit is exceeded
    * @throws {MorphAuthenticationError} If API key is missing or invalid
    *
    * @example
    * ```typescript
  * const setup = await morph.browser.profiles.createProfile({
  *   name: 'LinkedIn Production',
  *   repoId: 'owner/repo'
  * });
  * console.log(setup.session.debugUrl);
  * await setup.save();
    * ```
    */
  async createProfile(input) {
    return createProfile(input, this.config);
  }
  /**
   * List all profiles for the authenticated user.
   *
   * @param repoId - Optional repository ID to filter by
   * @returns Array of profiles
   *
   * @example
   * ```typescript
   * // List all profiles
   * const allProfiles = await morph.browser.profiles.listProfiles();
   *
   * // List profiles for a specific repo
   * const repoProfiles = await morph.browser.profiles.listProfiles('owner/repo');
   * ```
   */
  async listProfiles(repoId) {
    return listProfiles(this.config, repoId);
  }
  /**
   * Get a profile by ID with convenience methods.
   *
   * @param id - Profile ID
   * @returns Profile with attached methods
   * @throws {MorphNotFoundError} If profile is not found
   *
   * @example
   * ```typescript
   * const profile = await morph.browser.profiles.getProfile('profile-id');
   * const state = await profile.getState();
   * await profile.delete();
   * ```
   */
  async getProfile(id) {
    return getProfile(id, this.config);
  }
  /**
   * Update a profile by opening a live session (no rename).
   *
   * @param id - Profile ID
   * @returns Profile setup handle with live URL + save()
   */
  async updateProfile(id) {
    return updateProfile(id, this.config);
  }
  /**
   * Delete a profile.
   *
   * @param id - Profile ID
   * @throws {MorphNotFoundError} If profile is not found
   */
  async deleteProfile(id) {
    return deleteProfile(id, this.config);
  }
  /**
   * Start a browser session for profile setup.
   *
   * Returns a live URL where the user can sign into accounts.
   * After signing in, call `saveSession` to persist the state.
   *
   * @param input - Optional session parameters
   * @returns Session with debug URL
   *
   * @example
   * ```typescript
   * const session = await morph.browser.profiles.startSession();
   * console.log('Sign in at:', session.debugUrl);
   * // Open debugUrl in browser, user signs in...
   * await morph.browser.profiles.saveSession(session.sessionId, profile.id);
   * ```
   */
  async startSession(input) {
    return startProfileSession(this.config, input);
  }
  /**
   * Save browser state from a session to a profile.
   *
   * Call this after the user is done signing into accounts.
   * Extracts cookies, localStorage, and sessionStorage.
   *
   * @param sessionId - Browser session ID from startSession
   * @param profileId - Profile ID to save state to
   * @returns Updated profile with cookie domains
   */
  async saveSession(sessionId, profileId) {
    return saveProfileSession({ sessionId, profileId }, this.config);
  }
  /**
   * List available repo IDs (discovery).
   *
   * @returns Repo summaries with profile counts
   */
  async listRepos() {
    return listRepos(this.config);
  }
  /**
   * Get the presigned URL for a profile's state.
   *
   * Use this to download the raw state JSON for debugging
   * or to restore state manually.
   *
   * @param profileId - Profile ID
   * @returns State URL with expiry information
   */
  async getProfileState(profileId) {
    return getProfileState(profileId, this.config);
  }
};
function validateCreateInput(input) {
  if (!input.name || typeof input.name !== "string") {
    throw new MorphValidationError("name is required", "name");
  }
  const trimmedName = input.name.trim();
  if (trimmedName.length === 0) {
    throw new MorphValidationError("name cannot be empty", "name");
  }
  if (trimmedName.length > 100) {
    throw new MorphValidationError("name must be 100 characters or less", "name");
  }
  if (!input.repoId || typeof input.repoId !== "string") {
    throw new MorphValidationError("repoId is required", "repoId");
  }
  if (input.repoId.trim().length === 0) {
    throw new MorphValidationError("repoId cannot be empty", "repoId");
  }
}
function validateId(id, fieldName) {
  if (!id || typeof id !== "string") {
    throw new MorphValidationError(`${fieldName} is required`, fieldName);
  }
  if (id.trim().length === 0) {
    throw new MorphValidationError(`${fieldName} cannot be empty`, fieldName);
  }
}
async function createProfile(input, config = {}) {
  validateCreateInput(input);
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles`,
    {
      method: "POST",
      headers,
      body: JSON.stringify(transformCreateInput(input))
    },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiProfile = await response.json();
  const profile = transformProfile(apiProfile);
  const session = await startProfileSession(config, { profileId: profile.id });
  return buildProfileSetup(profile, session, config);
}
async function listProfiles(config = {}, repoId) {
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const url = repoId ? `${apiUrl}/profiles?repo_id=${encodeURIComponent(repoId)}` : `${apiUrl}/profiles`;
  const response = await fetchWithRetry(
    url,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const data = await response.json();
  return data.profiles.map(transformProfile);
}
async function getProfile(id, config = {}) {
  validateId(id, "id");
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/${encodeURIComponent(id)}`,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiProfile = await response.json();
  const profile = transformProfile(apiProfile);
  return {
    ...profile,
    getState: () => getProfileState(id, config),
    delete: () => deleteProfile(id, config)
  };
}
async function updateProfile(id, config = {}) {
  validateId(id, "id");
  const profile = await fetchProfile(id, config);
  const session = await startProfileSession(config, { profileId: profile.id });
  return buildProfileSetup(profile, session, config);
}
async function deleteProfile(id, config = {}) {
  validateId(id, "id");
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/${encodeURIComponent(id)}`,
    { method: "DELETE", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
}
async function startProfileSession(config = {}, input) {
  if (!config.apiKey) {
    throw new MorphAuthenticationError();
  }
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const body = input?.profileId ? { profile_id: input.profileId } : {};
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/session/start`,
    {
      method: "POST",
      headers,
      body: JSON.stringify(body)
    },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiSession = await response.json();
  return transformSession(apiSession);
}
async function saveProfileSession(input, config = {}) {
  validateId(input.sessionId, "sessionId");
  validateId(input.profileId, "profileId");
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/session/save`,
    {
      method: "POST",
      headers,
      body: JSON.stringify(transformSaveInput(input))
    },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiProfile = await response.json();
  return transformProfile(apiProfile);
}
async function listRepos(config = {}) {
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/repos`,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const data = await response.json();
  const repos = Array.isArray(data?.repos) ? data.repos : [];
  return repos.map((repo) => ({
    repoId: repo.repo_id,
    repoFullName: repo.repo_full_name,
    profileCount: repo.profile_count ?? 0
  }));
}
async function getProfileState(profileId, config = {}) {
  validateId(profileId, "profileId");
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/${encodeURIComponent(profileId)}/state`,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiState = await response.json();
  return transformStateResponse(apiState);
}
function buildHeaders(config) {
  const headers = { "Content-Type": "application/json" };
  if (config.apiKey) {
    headers["Authorization"] = `Bearer ${config.apiKey}`;
  }
  return headers;
}
async function fetchProfile(id, config) {
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
  const headers = buildHeaders(config);
  const response = await fetchWithRetry(
    `${apiUrl}/profiles/${encodeURIComponent(id)}`,
    { method: "GET", headers },
    config.retryConfig
  );
  if (!response.ok) {
    const errorText = await response.text().catch(() => response.statusText);
    const requestId = response.headers.get("x-request-id") || void 0;
    throw parseAPIError(response.status, errorText, requestId);
  }
  const apiProfile = await response.json();
  return transformProfile(apiProfile);
}
function buildProfileSetup(profile, session, config) {
  return {
    profile,
    session,
    save: () => saveProfileSession({ sessionId: session.sessionId, profileId: profile.id }, config)
  };
}

export {
  ProfilesClient,
  createProfile,
  listProfiles,
  getProfile,
  updateProfile,
  deleteProfile,
  startProfileSession,
  saveProfileSession,
  listRepos,
  getProfileState
};
//# sourceMappingURL=chunk-WAWGBDBT.js.map