'use strict';

var nodeFetchNativeWithAgent = require('node-fetch-native-with-agent');
var agent = require('node-fetch-native-with-agent/agent');
var query = require('./query');

class AppwriteException extends Error {
  constructor(message, code = 0, type = "", response = "") {
    super(message);
    this.name = "AppwriteException";
    this.message = message;
    this.code = code;
    this.type = type;
    this.response = response;
  }
}
function getUserAgent() {
  let ua = "AppwriteNodeJSSDK/21.1.0";
  const platform = [];
  if (typeof process !== "undefined") {
    if (typeof process.platform === "string")
      platform.push(process.platform);
    if (typeof process.arch === "string")
      platform.push(process.arch);
  }
  if (platform.length > 0) {
    ua += ` (${platform.join("; ")})`;
  }
  if (typeof navigator !== "undefined" && typeof navigator.userAgent === "string") {
    ua += ` ${navigator.userAgent}`;
  } else if (typeof globalThis.EdgeRuntime === "string") {
    ua += ` EdgeRuntime`;
  } else if (typeof process !== "undefined" && typeof process.version === "string") {
    ua += ` Node.js/${process.version}`;
  }
  return ua;
}
const _Client = class _Client {
  constructor() {
    this.config = {
      endpoint: "https://cloud.appwrite.io/v1",
      selfSigned: false,
      project: "",
      key: "",
      jwt: "",
      locale: "",
      session: "",
      forwardeduseragent: ""
    };
    this.headers = {
      "x-sdk-name": "Node.js",
      "x-sdk-platform": "server",
      "x-sdk-language": "nodejs",
      "x-sdk-version": "21.1.0",
      "user-agent": getUserAgent(),
      "X-Appwrite-Response-Format": "1.8.0"
    };
  }
  /**
   * Set Endpoint
   *
   * Your project endpoint
   *
   * @param {string} endpoint
   *
   * @returns {this}
   */
  setEndpoint(endpoint) {
    if (!endpoint.startsWith("http://") && !endpoint.startsWith("https://")) {
      throw new AppwriteException("Invalid endpoint URL: " + endpoint);
    }
    this.config.endpoint = endpoint;
    return this;
  }
  /**
   * Set self-signed
   *
   * @param {boolean} selfSigned
   *
   * @returns {this}
   */
  setSelfSigned(selfSigned) {
    if (typeof globalThis.EdgeRuntime !== "undefined") {
      console.warn("setSelfSigned is not supported in edge runtimes.");
    }
    this.config.selfSigned = selfSigned;
    return this;
  }
  /**
   * Add header
   *
   * @param {string} header
   * @param {string} value
   *
   * @returns {this}
   */
  addHeader(header, value) {
    this.headers[header.toLowerCase()] = value;
    return this;
  }
  /**
   * Set Project
   *
   * Your project ID
   *
   * @param value string
   *
   * @return {this}
   */
  setProject(value) {
    this.headers["X-Appwrite-Project"] = value;
    this.config.project = value;
    return this;
  }
  /**
   * Set Key
   *
   * Your secret API key
   *
   * @param value string
   *
   * @return {this}
   */
  setKey(value) {
    this.headers["X-Appwrite-Key"] = value;
    this.config.key = value;
    return this;
  }
  /**
   * Set JWT
   *
   * Your secret JSON Web Token
   *
   * @param value string
   *
   * @return {this}
   */
  setJWT(value) {
    this.headers["X-Appwrite-JWT"] = value;
    this.config.jwt = value;
    return this;
  }
  /**
   * Set Locale
   *
   * @param value string
   *
   * @return {this}
   */
  setLocale(value) {
    this.headers["X-Appwrite-Locale"] = value;
    this.config.locale = value;
    return this;
  }
  /**
   * Set Session
   *
   * The user session to authenticate with
   *
   * @param value string
   *
   * @return {this}
   */
  setSession(value) {
    this.headers["X-Appwrite-Session"] = value;
    this.config.session = value;
    return this;
  }
  /**
   * Set ForwardedUserAgent
   *
   * The user agent string of the client that made the request
   *
   * @param value string
   *
   * @return {this}
   */
  setForwardedUserAgent(value) {
    this.headers["X-Forwarded-User-Agent"] = value;
    this.config.forwardeduseragent = value;
    return this;
  }
  prepareRequest(method, url, headers = {}, params = {}) {
    method = method.toUpperCase();
    headers = Object.assign({}, this.headers, headers);
    let options = {
      method,
      headers,
      ...agent.createAgent(this.config.endpoint, { rejectUnauthorized: !this.config.selfSigned })
    };
    if (method === "GET") {
      for (const [key, value] of Object.entries(_Client.flatten(params))) {
        url.searchParams.append(key, value);
      }
    } else {
      switch (headers["content-type"]) {
        case "application/json":
          options.body = JSON.stringify(params);
          break;
        case "multipart/form-data":
          const formData = new nodeFetchNativeWithAgent.FormData();
          for (const [key, value] of Object.entries(params)) {
            if (value instanceof nodeFetchNativeWithAgent.File) {
              formData.append(key, value, value.name);
            } else if (Array.isArray(value)) {
              for (const nestedValue of value) {
                formData.append(`${key}[]`, nestedValue);
              }
            } else {
              formData.append(key, value);
            }
          }
          options.body = formData;
          delete headers["content-type"];
          break;
      }
    }
    return { uri: url.toString(), options };
  }
  async chunkedUpload(method, url, headers = {}, originalPayload = {}, onProgress) {
    const [fileParam, file] = Object.entries(originalPayload).find(([_, value]) => value instanceof nodeFetchNativeWithAgent.File) ?? [];
    if (!file || !fileParam) {
      throw new Error("File not found in payload");
    }
    if (file.size <= _Client.CHUNK_SIZE) {
      return await this.call(method, url, headers, originalPayload);
    }
    let start = 0;
    let response = null;
    while (start < file.size) {
      let end = start + _Client.CHUNK_SIZE;
      if (end >= file.size) {
        end = file.size;
      }
      headers["content-range"] = `bytes ${start}-${end - 1}/${file.size}`;
      const chunk = file.slice(start, end);
      let payload = { ...originalPayload };
      payload[fileParam] = new nodeFetchNativeWithAgent.File([chunk], file.name);
      response = await this.call(method, url, headers, payload);
      if (onProgress && typeof onProgress === "function") {
        onProgress({
          $id: response.$id,
          progress: Math.round(end / file.size * 100),
          sizeUploaded: end,
          chunksTotal: Math.ceil(file.size / _Client.CHUNK_SIZE),
          chunksUploaded: Math.ceil(end / _Client.CHUNK_SIZE)
        });
      }
      if (response && response.$id) {
        headers["x-appwrite-id"] = response.$id;
      }
      start = end;
    }
    return response;
  }
  async ping() {
    return this.call("GET", new URL(this.config.endpoint + "/ping"));
  }
  async redirect(method, url, headers = {}, params = {}) {
    const { uri, options } = this.prepareRequest(method, url, headers, params);
    const response = await nodeFetchNativeWithAgent.fetch(uri, {
      ...options,
      redirect: "manual"
    });
    if (response.status !== 301 && response.status !== 302) {
      throw new AppwriteException("Invalid redirect", response.status);
    }
    return response.headers.get("location") || "";
  }
  async call(method, url, headers = {}, params = {}, responseType = "json") {
    var _a, _b;
    const { uri, options } = this.prepareRequest(method, url, headers, params);
    let data = null;
    const response = await nodeFetchNativeWithAgent.fetch(uri, options);
    const warnings = response.headers.get("x-appwrite-warning");
    if (warnings) {
      warnings.split(";").forEach((warning) => console.warn("Warning: " + warning));
    }
    if ((_a = response.headers.get("content-type")) == null ? void 0 : _a.includes("application/json")) {
      data = await response.json();
    } else if (responseType === "arrayBuffer") {
      data = await response.arrayBuffer();
    } else {
      data = {
        message: await response.text()
      };
    }
    if (400 <= response.status) {
      let responseText = "";
      if (((_b = response.headers.get("content-type")) == null ? void 0 : _b.includes("application/json")) || responseType === "arrayBuffer") {
        responseText = JSON.stringify(data);
      } else {
        responseText = data == null ? void 0 : data.message;
      }
      throw new AppwriteException(data == null ? void 0 : data.message, response.status, data == null ? void 0 : data.type, responseText);
    }
    return data;
  }
  static flatten(data, prefix = "") {
    let output = {};
    for (const [key, value] of Object.entries(data)) {
      let finalKey = prefix ? prefix + "[" + key + "]" : key;
      if (Array.isArray(value)) {
        output = { ...output, ..._Client.flatten(value, finalKey) };
      } else {
        output[finalKey] = value;
      }
    }
    return output;
  }
};
_Client.CHUNK_SIZE = 1024 * 1024 * 5;
let Client = _Client;

Object.defineProperty(exports, 'Query', {
  enumerable: true,
  get: function () { return query.Query; }
});
exports.AppwriteException = AppwriteException;
exports.Client = Client;
//# sourceMappingURL=out.js.map
//# sourceMappingURL=client.js.map