/**
 * Keychain Manager for DashCaddy
 * Provides secure credential storage using OS-native keychains
 * Falls back to encrypted file storage if keychain is unavailable
 */

const { execSync, execFileSync } = require('child_process');
const os = require('os');
const crypto = require('crypto');

const SERVICE_NAME = 'DashCaddy';
const ACCOUNT_PREFIX = 'dashcaddy';

class KeychainManager {
  constructor() {
    this.platform = os.platform();
    this.available = this.checkAvailability();
  }

  /**
   * Check if OS keychain is available
   * @returns {boolean}
   */
  checkAvailability() {
    try {
      if (this.platform === 'win32') {
        // Check if PowerShell is available
        execSync('powershell -Command "Get-Command Get-Credential"', { stdio: 'ignore' });
        return true;
      } else if (this.platform === 'darwin') {
        // Check if security command is available
        execSync('which security', { stdio: 'ignore' });
        return true;
      } else if (this.platform === 'linux') {
        // Check if secret-tool (libsecret) is available
        try {
          execSync('which secret-tool', { stdio: 'ignore' });
          return true;
        } catch {
          // Try gnome-keyring
          execSync('which gnome-keyring-daemon', { stdio: 'ignore' });
          return true;
        }
      }
      return false;
    } catch {
      console.warn('[Keychain] OS keychain not available, will use encrypted file storage');
      return false;
    }
  }

  /**
   * Store a credential in the OS keychain
   * @param {string} key - Credential identifier
   * @param {string} value - Credential value
   * @returns {Promise<boolean>} Success status
   */
  async store(key, value) {
    if (!this.available) {
      return false;
    }

    const account = `${ACCOUNT_PREFIX}.${key}`;

    try {
      if (this.platform === 'win32') {
        return await this.storeWindows(account, value);
      } else if (this.platform === 'darwin') {
        return await this.storeMacOS(account, value);
      } else if (this.platform === 'linux') {
        return await this.storeLinux(account, value);
      }
      return false;
    } catch (error) {
      console.error(`[Keychain] Failed to store ${key}:`, error.message);
      return false;
    }
  }

  /**
   * Retrieve a credential from the OS keychain
   * @param {string} key - Credential identifier
   * @returns {Promise<string|null>} Credential value or null
   */
  async retrieve(key) {
    if (!this.available) {
      return null;
    }

    const account = `${ACCOUNT_PREFIX}.${key}`;

    try {
      if (this.platform === 'win32') {
        return await this.retrieveWindows(account);
      } else if (this.platform === 'darwin') {
        return await this.retrieveMacOS(account);
      } else if (this.platform === 'linux') {
        return await this.retrieveLinux(account);
      }
      return null;
    } catch (error) {
      console.error(`[Keychain] Failed to retrieve ${key}:`, error.message);
      return null;
    }
  }

  /**
   * Delete a credential from the OS keychain
   * @param {string} key - Credential identifier
   * @returns {Promise<boolean>} Success status
   */
  async delete(key) {
    if (!this.available) {
      return false;
    }

    const account = `${ACCOUNT_PREFIX}.${key}`;

    try {
      if (this.platform === 'win32') {
        return await this.deleteWindows(account);
      } else if (this.platform === 'darwin') {
        return await this.deleteMacOS(account);
      } else if (this.platform === 'linux') {
        return await this.deleteLinux(account);
      }
      return false;
    } catch (error) {
      console.error(`[Keychain] Failed to delete ${key}:`, error.message);
      return false;
    }
  }

  // Windows Credential Manager implementation (uses execFileSync to prevent injection)
  async storeWindows(account, value) {
    execFileSync('cmdkey', [`/generic:${SERVICE_NAME}:${account}`, `/user:${account}`, `/pass:${value}`], { stdio: 'ignore' });
    return true;
  }

  async retrieveWindows(account) {
    try {
      const result = execFileSync('cmdkey', [`/list:${SERVICE_NAME}:${account}`], { encoding: 'utf8' });
      const match = result.match(/Password:\s*(.+)/);
      return match ? match[1].trim() : null;
    } catch {
      return null;
    }
  }

  async deleteWindows(account) {
    execFileSync('cmdkey', [`/delete:${SERVICE_NAME}:${account}`], { stdio: 'ignore' });
    return true;
  }

  // macOS Keychain implementation (uses execFileSync to prevent injection)
  async storeMacOS(account, value) {
    try {
      execFileSync('security', ['delete-generic-password', '-s', SERVICE_NAME, '-a', account], { stdio: 'ignore' });
    } catch {
      // Ignore if doesn't exist
    }
    execFileSync('security', ['add-generic-password', '-s', SERVICE_NAME, '-a', account, '-w', value], { stdio: 'ignore' });
    return true;
  }

  async retrieveMacOS(account) {
    try {
      const result = execFileSync('security', ['find-generic-password', '-s', SERVICE_NAME, '-a', account, '-w'], { encoding: 'utf8' });
      return result.trim() || null;
    } catch {
      return null;
    }
  }

  async deleteMacOS(account) {
    execFileSync('security', ['delete-generic-password', '-s', SERVICE_NAME, '-a', account], { stdio: 'ignore' });
    return true;
  }

  // Linux Secret Service implementation (uses execFileSync + stdin to prevent injection)
  async storeLinux(account, value) {
    try {
      execFileSync('secret-tool', ['store', `--label=${SERVICE_NAME}:${account}`, 'service', SERVICE_NAME, 'account', account], {
        input: value,
        stdio: ['pipe', 'ignore', 'ignore']
      });
      return true;
    } catch {
      return false;
    }
  }

  async retrieveLinux(account) {
    try {
      const result = execFileSync('secret-tool', ['lookup', 'service', SERVICE_NAME, 'account', account], { encoding: 'utf8' });
      return result.trim() || null;
    } catch {
      return null;
    }
  }

  async deleteLinux(account) {
    try {
      execFileSync('secret-tool', ['clear', 'service', SERVICE_NAME, 'account', account], { stdio: 'ignore' });
      return true;
    } catch {
      return false;
    }
  }
}

module.exports = new KeychainManager();
