const fs = require('fs');
const path = require('path');
const { promisify } = require('util');

const copyFile = promisify(fs.copyFile);
const mkdir = promisify(fs.mkdir);
const readdir = promisify(fs.readdir);

/**
 * FileDeployer - Handles copying dashboard and API files to installation directory
 *
 * In dev mode: reads from sibling directories (../../../status, ../../../dashcaddy-api)
 * In packaged exe: reads from extraResources (process.resourcesPath/status, .../dashcaddy-api)
 */
class FileDeployer {
  constructor() {
    this._resolveSourcePaths();
  }

  _resolveSourcePaths() {
    let app;
    try {
      app = require('electron').app;
    } catch {
      // Not in Electron context
    }

    const isPackaged = app?.isPackaged || false;

    if (isPackaged) {
      // Packaged exe: files are in extraResources
      this.dashboardSource = path.join(process.resourcesPath, 'status');
      this.apiSource = path.join(process.resourcesPath, 'dashcaddy-api');
    } else {
      // Dev mode: sibling directories in the project tree
      this.dashboardSource = path.join(__dirname, '../../../status');
      this.apiSource = path.join(__dirname, '../../../dashcaddy-api');
    }
  }

  /**
   * Copy directory recursively, skipping node_modules, .git, and test files
   */
  async copyDirectory(src, dest, progressCallback = null) {
    try {
      await mkdir(dest, { recursive: true });

      const entries = await readdir(src, { withFileTypes: true });
      let copiedCount = 0;

      for (const entry of entries) {
        const srcPath = path.join(src, entry.name);
        const destPath = path.join(dest, entry.name);

        // Skip unnecessary directories and files
        if (['node_modules', '.git', '__tests__', 'test', '.nyc_output', 'coverage'].includes(entry.name)) {
          continue;
        }
        // Skip test files
        if (entry.name.endsWith('.test.js') || entry.name.endsWith('.spec.js')) {
          continue;
        }

        if (entry.isDirectory()) {
          const subResult = await this.copyDirectory(srcPath, destPath, progressCallback);
          if (subResult.success) copiedCount += subResult.filesCopied;
        } else {
          await copyFile(srcPath, destPath);
          copiedCount++;

          if (progressCallback) {
            progressCallback({
              type: 'file',
              source: srcPath,
              destination: destPath,
              count: copiedCount
            });
          }
        }
      }

      return { success: true, filesCopied: copiedCount };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }

  /**
   * Deploy dashboard files to installation directory
   */
  async deployDashboard(installPath, progressCallback = null) {
    try {
      const dashboardDest = path.join(installPath, 'sites', 'status');

      if (progressCallback) {
        progressCallback({
          type: 'start',
          message: 'Deploying dashboard files...',
          source: this.dashboardSource,
          destination: dashboardDest
        });
      }

      // Verify source exists
      if (!fs.existsSync(this.dashboardSource)) {
        throw new Error(`Dashboard source not found at: ${this.dashboardSource}`);
      }

      const result = await this.copyDirectory(
        this.dashboardSource,
        dashboardDest,
        progressCallback
      );

      if (!result.success) {
        throw new Error(result.error);
      }

      if (progressCallback) {
        progressCallback({
          type: 'complete',
          message: `Dashboard deployed (${result.filesCopied} files)`,
          filesCopied: result.filesCopied
        });
      }

      return {
        success: true,
        path: dashboardDest,
        filesCopied: result.filesCopied
      };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }

  /**
   * Deploy API server files to installation directory
   */
  async deployAPI(installPath, progressCallback = null) {
    try {
      const apiDest = path.join(installPath, 'sites', 'dashcaddy-api');

      if (progressCallback) {
        progressCallback({
          type: 'start',
          message: 'Deploying API server files...',
          source: this.apiSource,
          destination: apiDest
        });
      }

      if (!fs.existsSync(this.apiSource)) {
        throw new Error(`API source not found at: ${this.apiSource}`);
      }

      const result = await this.copyDirectory(
        this.apiSource,
        apiDest,
        progressCallback
      );

      if (!result.success) {
        throw new Error(result.error);
      }

      if (progressCallback) {
        progressCallback({
          type: 'complete',
          message: `API server deployed (${result.filesCopied} files)`,
          filesCopied: result.filesCopied
        });
      }

      return {
        success: true,
        path: apiDest,
        filesCopied: result.filesCopied
      };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }

  /**
   * Deploy both dashboard and API files
   */
  async deployComplete(installPath, progressCallback = null) {
    try {
      const dashboardResult = await this.deployDashboard(installPath, progressCallback);
      if (!dashboardResult.success) {
        throw new Error(`Dashboard deployment failed: ${dashboardResult.error}`);
      }

      const apiResult = await this.deployAPI(installPath, progressCallback);
      if (!apiResult.success) {
        throw new Error(`API deployment failed: ${apiResult.error}`);
      }

      return {
        success: true,
        dashboard: dashboardResult,
        api: apiResult
      };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }

  /**
   * Check if source directories exist
   */
  async validateSources() {
    const checks = {
      dashboard: fs.existsSync(this.dashboardSource),
      api: fs.existsSync(this.apiSource)
    };

    return {
      valid: checks.dashboard && checks.api,
      checks,
      paths: {
        dashboard: this.dashboardSource,
        api: this.apiSource
      }
    };
  }
}

module.exports = FileDeployer;
