Source: github/repository.js

/**
 * @fileoverview Repository operations for GitHub
 * @license Apache-2.0
 * @version 3.0.0
 * @author Michael Hay <michael.hay@mediumroast.io>
 * @copyright 2025 Mediumroast, Inc. All rights reserved.
 */

import ResponseFactory from './response.js';
import { encodeContent } from './utils.js';

/**
 * Manages low-level GitHub repository operations
 */
class RepositoryManager {
  /**
   * @constructor
   * @param {Object} octokit - Octokit instance
   * @param {String} orgName - GitHub organization name
   * @param {String} repoName - GitHub repository name
   */
  constructor(octokit, orgName, repoName) {
    this.octokit = octokit;
    this.orgName = orgName;
    this.repoName = repoName;
  }

  /**
   * Gets content from the repository
   * @param {String} path - Path to the content
   * @param {String} ref - Branch or commit reference
   * @returns {Promise<Array>} ResponseFactory result
   */
  async getContent(path, ref) {
    try {
      const response = await this.octokit.rest.repos.getContent({
        owner: this.orgName,
        repo: this.repoName,
        path,
        ref
      });
      return ResponseFactory.success(`Retrieved content at ${path}`, response.data);
    } catch (err) {
      return ResponseFactory.error(`Failed to get content at ${path}: ${err.message}`, err);
    }
  }

  /**
   * Creates or updates a file in the repository
   * @param {String} path - Path to the file
   * @param {String|Object} content - Content to write (will be encoded)
   * @param {String} message - Commit message
   * @param {String} branch - Branch name
   * @param {String} sha - SHA of the file (if updating)
   * @returns {Promise<Array>} ResponseFactory result
   */
  async createOrUpdateFile(path, content, message, branch, sha = null) {
    try {
      const params = {
        owner: this.orgName,
        repo: this.repoName,
        path,
        message,
        content: encodeContent(content),
        branch
      };
      
      if (sha) params.sha = sha;
      
      const response = await this.octokit.rest.repos.createOrUpdateFileContents(params);
      return ResponseFactory.success(`Updated ${path}`, response.data);
    } catch (err) {
      return ResponseFactory.error(`Failed to update ${path}: ${err.message}`, err);
    }
  }

  /**
   * Deletes a file from the repository
   * @param {String} path - Path to the file
   * @param {String} message - Commit message
   * @param {String} branch - Branch name
   * @param {String} sha - SHA of the file
   * @returns {Promise<Array>} ResponseFactory result
   */
  async deleteFile(path, message, branch, sha) {
    try {
      const response = await this.octokit.rest.repos.deleteFile({
        owner: this.orgName,
        repo: this.repoName,
        path,
        message,
        branch,
        sha
      });
      return ResponseFactory.success(`Deleted ${path}`, response.data);
    } catch (err) {
      return ResponseFactory.error(`Failed to delete ${path}: ${err.message}`, err);
    }
  }

  /**
   * Gets user information
   * @returns {Promise<Array>} ResponseFactory result
   */
  async getUser() {
    try {
      const response = await this.octokit.rest.users.getAuthenticated();
      return ResponseFactory.success('Successfully retrieved user information', response.data);
    } catch (err) {
      return ResponseFactory.error(`Failed to get user: ${err.message}`, err.message);
    }
  }
  
  /**
   * Gets all users (collaborators) for the repository
   * @returns {Promise<Array>} ResponseFactory result
   */
  async getCollaborators() {
    try {
      const response = await this.octokit.rest.repos.listCollaborators({
        owner: this.orgName,
        repo: this.repoName,
        affiliation: 'all'
      });
      return ResponseFactory.success('Successfully retrieved collaborators', response.data);
    } catch (err) {
      return ResponseFactory.error(`Failed to get collaborators: ${err.message}`, err.message);
    }
  }

  /**
   * Gets billing information for GitHub Actions
   * @returns {Promise<Array>} ResponseFactory result
   */
  async getActionsBilling() {
    try {
      const response = await this.octokit.rest.billing.getGithubActionsBillingOrg({
        org: this.orgName,
      });
      return ResponseFactory.success('Successfully retrieved actions billing', response.data);
    } catch (err) {
      return ResponseFactory.error(`Failed to get actions billing: ${err.message}`, err.message, 404);
    }
  }

  /**
   * Gets billing information for GitHub Storage
   * @returns {Promise<Array>} ResponseFactory result
   */
  async getStorageBilling() {
    try {
      const response = await this.octokit.rest.billing.getSharedStorageBillingOrg({
        org: this.orgName,
      });
      return ResponseFactory.success('Successfully retrieved storage billing', response.data);
    } catch (err) {
      return ResponseFactory.error(`Failed to get storage billing: ${err.message}`, err.message, 404);
    }
  }

  /**
   * Creates a repository in the organization
   * @param {String} description - Repository description
   * @returns {Promise<Array>} ResponseFactory result
   */
  async createRepository(description) {
    try {
      const response = await this.octokit.rest.repos.createInOrg({
        org: this.orgName,
        name: this.repoName,
        description: description,
        private: true
      });
      return ResponseFactory.success(`Created repository ${this.repoName}`, response.data);
    } catch (err) {
      return ResponseFactory.error(`Failed to create repository: ${err.message}`, err.message);
    }
  }

  /**
   * Gets organization information
   * @returns {Promise<Array>} ResponseFactory result
   */
  async getOrganization() {
    try {
      const response = await this.octokit.rest.orgs.get({
        org: this.orgName
      });
      return ResponseFactory.success(`Retrieved organization ${this.orgName}`, response.data);
    } catch (err) {
      return ResponseFactory.error(`Failed to get organization: ${err.message}`, err.message);
    }
  }
}

export default RepositoryManager;