/**
 * Plugin 命令实现
 * 支持插件的上传(publish)和下载(install)
 */

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const https = require('https');
const http = require('http');
const { DEFAULT_REPO, shouldIgnore } = require('../utils/plugin-config');

/**
 * 递归复制目录（带过滤）
 */
function copyDirRecursive(src, dest, ignorePatterns = []) {
  if (!fs.existsSync(src)) return;

  fs.mkdirSync(dest, { recursive: true });

  const entries = fs.readdirSync(src, { withFileTypes: true });

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

    // 检查是否忽略
    if (shouldIgnore(entry.name)) {
      console.log(`  Ignoring: ${entry.name}`);
      continue;
    }

    if (entry.isDirectory()) {
      copyDirRecursive(srcPath, destPath, ignorePatterns);
    } else {
      fs.copyFileSync(srcPath, destPath);
    }
  }
}

/**
 * 解析 Git URL 获取信息
 */
function parseGitUrl(url) {
  // 支持多种格式
  const patterns = [
    /^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/,
    /^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/,
  ];

  for (const pattern of patterns) {
    const match = url.match(pattern);
    if (match) {
      return { owner: match[1], repo: match[2] };
    }
  }
  return null;
}

/**
 * 执行 Git 命令
 */
function gitCommand(args, cwd) {
  try {
    return execSync(`git ${args}`, { cwd, encoding: 'utf-8', stdio: 'pipe' });
  } catch (err) {
    return err.stdout || err.stderr || '';
  }
}

/**
 * 下载文件
 */
function downloadFile(url, dest) {
  return new Promise((resolve, reject) => {
    const file = fs.createWriteStream(dest);
    const protocol = url.startsWith('https') ? https : http;

    protocol
      .get(url, (response) => {
        if (response.statusCode === 301 || response.statusCode === 302) {
          // 处理重定向
          file.close();
          downloadFile(response.headers.location, dest).then(resolve).catch(reject);
          return;
        }

        if (response.statusCode !== 200) {
          file.close();
          reject(new Error(`HTTP ${response.statusCode}`));
          return;
        }

        response.pipe(file);
        file.on('finish', () => {
          file.close();
          resolve();
        });
      })
      .on('error', (err) => {
        file.close();
        fs.unlink(dest, () => {});
        reject(err);
      });
  });
}

/**
 * 发布插件到 Git
 */
async function publishCommand(pluginName, options) {
  // 支持 .agent/plugins 和 plugins 两个目录
  const agentPluginsDir = path.resolve(process.cwd(), '.agent', 'plugins');
  const localPluginsDir = path.resolve(process.cwd(), 'plugins');
  const pluginsDir = fs.existsSync(agentPluginsDir) ? agentPluginsDir : localPluginsDir;
  const pluginPath = path.join(pluginsDir, `${pluginName}.js`);
  const pluginSourceDir = path.join(pluginsDir, pluginName);

  // 检查插件是否存在（可以是 .js 文件或目录）
  if (!fs.existsSync(pluginPath) && !fs.existsSync(pluginSourceDir)) {
    console.error(`Plugin not found: ${pluginName}`);
    console.error(`Searched in: ${pluginsDir}`);
    console.error('Available plugins:');
    if (fs.existsSync(pluginsDir)) {
      fs.readdirSync(pluginsDir).forEach((f) => {
        if (f.endsWith('.js')) {
          console.error(`  - ${f.replace('.js', '')} (file)`);
        } else if (fs.statSync(path.join(pluginsDir, f)).isDirectory()) {
          console.error(`  - ${f} (directory)`);
        }
      });
    }
    if (fs.existsSync(localPluginsDir) && localPluginsDir !== pluginsDir) {
      fs.readdirSync(localPluginsDir).forEach((f) => {
        if (fs.statSync(path.join(localPluginsDir, f)).isDirectory()) {
          console.error(`  - ${f} (directory)`);
        } else if (f.endsWith('.js')) {
          console.error(`  - ${f.replace('.js', '')} (file)`);
        }
      });
    }
    process.exit(1);
  }

  const repo = options.repo || DEFAULT_REPO;
  const tmpDir = path.join(require('os').tmpdir(), `foliko-plugin-publish-${Date.now()}`);

  try {
    console.log(`Publishing plugin "${pluginName}" to ${repo}...`);

    // 1. 克隆仓库（如果不存在）或拉取更新
    fs.mkdirSync(tmpDir, { recursive: true });

    const repoInfo = parseGitUrl(repo);
    if (!repoInfo) {
      console.error('Invalid repository URL');
      process.exit(1);
    }

    // 尝试克隆
    let isNewRepo = false;
    try {
      console.log('Cloning repository...');
      gitCommand(`clone ${repo} "${tmpDir}" --depth 1`, process.cwd());
    } catch (err) {
      // 仓库可能为空，尝试初始化
      console.log('Initializing new repository...');
      fs.mkdirSync(tmpDir, { recursive: true });
      gitCommand('init', tmpDir);
      gitCommand(`remote add origin ${repo}`, tmpDir);
      isNewRepo = true;
    }

    // 2. 创建插件目录
    const pluginDir = path.join(tmpDir, pluginName);
    fs.mkdirSync(pluginDir, { recursive: true });

    // 3. 复制插件（整个目录或单个文件）
    let pluginContent = null;
    if (fs.existsSync(pluginSourceDir) && fs.statSync(pluginSourceDir).isDirectory()) {
      // 插件在子目录中
      console.log('Copying plugin directory...');
      copyDirRecursive(pluginSourceDir, pluginDir);

      // 尝试从主 js 文件读取描述
      const mainJsPath = path.join(pluginSourceDir, `${pluginName}.js`);
      if (fs.existsSync(mainJsPath)) {
        pluginContent = fs.readFileSync(mainJsPath, 'utf-8');
      }
    } else {
      // 单个插件文件
      console.log('Copying plugin file...');
      pluginContent = fs.readFileSync(pluginPath, 'utf-8');
      const targetPath = path.join(pluginDir, `${pluginName}.js`);
      fs.writeFileSync(targetPath, pluginContent);

      // 复制配置文件（如果存在）
      const configPath = path.join(pluginsDir, `${pluginName}.json`);
      if (fs.existsSync(configPath)) {
        fs.copyFileSync(configPath, path.join(pluginDir, `${pluginName}.json`));
      }
    }

    // 4. 创建 README.md（如果没有）
    const readmePath = path.join(pluginDir, 'README.md');
    if (!fs.existsSync(readmePath)) {
      // 尝试从插件文件中提取描述
      const descMatch =
        pluginContent?.match(/\*\*Description\*\*:\s*(.+)/) ||
        pluginContent?.match(/description[:\s]+(.+)/i);
      const desc = descMatch ? descMatch[1] : `Foliko plugin: ${pluginName}`;
      fs.writeFileSync(readmePath, `# ${pluginName}\n\n${desc}\n`);
    }

    // 6. Git 提交和推送
    gitCommand('add .', tmpDir);

    const status = gitCommand('status --porcelain', tmpDir);
    if (!status.trim()) {
      console.log('No changes to commit.');
      return;
    }

    gitCommand(`commit -m "Add/update plugin: ${pluginName}"`, tmpDir);
    gitCommand(`push ${isNewRepo ? '-u' : ''} origin main`, tmpDir);

    console.log(`\nPlugin "${pluginName}" published successfully!`);
    console.log(`Repository: ${repo}`);
    console.log(`Path: ${pluginName}/${pluginName}.js`);
  } catch (err) {
    console.error('Publish failed:', err.message);
    process.exit(1);
  } finally {
    // 清理临时目录
    fs.rmSync(tmpDir, { recursive: true, force: true });
  }
}

/**
 * 从 Git 安装插件
 */
async function installCommand(pluginName, options) {
  const repo = options.repo || DEFAULT_REPO;
  const tmpDir = path.join(require('os').tmpdir(), `foliko-plugin-install-${Date.now()}`);
  const localPluginsDir = path.resolve(process.cwd(), 'plugins');

  try {
    console.log(`Installing plugin "${pluginName}" from ${repo}...`);

    // 1. 克隆仓库
    console.log('Fetching plugin repository...');
    fs.mkdirSync(tmpDir, { recursive: true });
    gitCommand(`clone ${repo} "${tmpDir}" --depth 1`, process.cwd());

    // 2. 检查插件目录/文件
    const pluginDir = path.join(tmpDir, pluginName);
    let sourcePath;

    if (fs.existsSync(pluginDir) && fs.statSync(pluginDir).isDirectory()) {
      // 插件在子目录中
      sourcePath = path.join(pluginDir, `${pluginName}.js`);
    } else {
      // 插件在仓库根目录
      sourcePath = path.join(tmpDir, `${pluginName}.js`);
    }

    if (!fs.existsSync(sourcePath)) {
      // 列出可用插件
      console.error(`Plugin "${pluginName}" not found in repository.`);
      console.error('\nAvailable plugins:');

      const repos = fs.readdirSync(tmpDir).filter((f) => {
        const fullPath = path.join(tmpDir, f);
        return fs.statSync(fullPath).isDirectory();
      });

      if (repos.length === 0) {
        // 检查根目录的 js 文件
        fs.readdirSync(tmpDir)
          .filter((f) => f.endsWith('.js') && !f.startsWith('.'))
          .forEach((f) => console.error(`  - ${f.replace('.js', '')}`));
      } else {
        repos.forEach((r) => console.error(`  - ${r}`));
      }

      process.exit(1);
    }

    // 3. 确保本地 plugins 目录存在
    if (!fs.existsSync(localPluginsDir)) {
      fs.mkdirSync(localPluginsDir, { recursive: true });
    }

    // 4. 复制插件文件
    const targetPath = path.join(localPluginsDir, `${pluginName}.js`);
    fs.copyFileSync(sourcePath, targetPath);
    console.log(`Plugin copied to: ${targetPath}`);

    // 5. 复制配置文件（如果存在）
    const configSource = path.join(path.dirname(sourcePath), `${pluginName}.json`);
    if (fs.existsSync(configSource)) {
      const configTarget = path.join(localPluginsDir, `${pluginName}.json`);
      fs.copyFileSync(configSource, configTarget);
      console.log(`Config copied to: ${configTarget}`);
    }

    console.log(`\nPlugin "${pluginName}" installed successfully!`);
  } catch (err) {
    console.error('Install failed:', err.message);
    process.exit(1);
  } finally {
    // 清理临时目录
    fs.rmSync(tmpDir, { recursive: true, force: true });
  }
}

/**
 * 列出远程仓库中的插件
 */
async function listCommand(options) {
  const repo = options.repo || DEFAULT_REPO;

  try {
    console.log(`Fetching plugins from ${repo}...`);

    const repoInfo = parseGitUrl(repo);
    if (!repoInfo) {
      console.error('Invalid repository URL');
      process.exit(1);
    }

    // 使用 GitHub API 获取仓库内容
    const apiUrl = `https://api.github.com/repos/${repoInfo.owner}/${repoInfo.repo}/contents`;

    const response = await fetch(apiUrl);

    if (!response.ok) {
      if (response.status === 404) {
        console.error('Repository not found or is empty.');
      } else {
        console.error(`GitHub API error: ${response.status}`);
      }
      process.exit(1);
    }

    const contents = await response.json();

    if (!Array.isArray(contents) || contents.length === 0) {
      console.log('No plugins found in repository.');
      return;
    }

    console.log(`\nPlugins in ${repo}:\n`);
    console.log('Name              Type      Description');
    console.log('----------------  --------  ------------------------------------------');

    for (const item of contents) {
      if (item.type === 'dir') {
        // 尝试读取 README
        let desc = '-';
        try {
          const readmeUrl = `https://raw.githubusercontent.com/${repoInfo.owner}/${repoInfo.repo}/main/${item.name}/README.md`;
          const readmeResp = await fetch(readmeUrl);
          if (readmeResp.ok) {
            const readmeText = await readmeResp.text();
            const lines = readmeText.split('\n').filter((l) => l.trim());
            if (lines.length > 1) {
              desc = lines.slice(1).join(' ').slice(0, 40);
            }
          }
        } catch (e) {}

        console.log(`${item.name.padEnd(16)}  plugin    ${desc}`);
      } else if (item.type === 'file' && item.name.endsWith('.js')) {
        const name = item.name.replace('.js', '');
        console.log(`${name.padEnd(16)}  plugin    (root file)`);
      }
    }
  } catch (err) {
    console.error('List failed:', err.message);
    process.exit(1);
  }
}

/**
 * 插件命令主入口
 */
async function pluginCommand(args) {
  let subcommand = args[0];

  // 处理帮助选项
  if (subcommand === '--help' || subcommand === '-h' || subcommand === 'help') {
    printHelp();
    return;
  }

  if (!subcommand) {
    printHelp();
    return;
  }

  const options = {
    repo: process.env.FOLIKO_PLUGIN_REPO || DEFAULT_REPO,
  };

  // 解析全局选项
  const remainingArgs = [];
  for (let i = 1; i < args.length; i++) {
    if (args[i] === '--repo' && args[i + 1]) {
      options.repo = args[i + 1];
      i++;
    } else {
      remainingArgs.push(args[i]);
    }
  }

  switch (subcommand) {
    case 'publish':
    case 'push': {
      const pluginName = remainingArgs[0];
      if (!pluginName) {
        console.error('Plugin name required: foliko plugin publish <name>');
        process.exit(1);
      }
      await publishCommand(pluginName, options);
      break;
    }

    case 'install':
    case 'add': {
      const pluginName = remainingArgs[0];
      if (!pluginName) {
        console.error('Plugin name required: foliko plugin install <name>');
        process.exit(1);
      }
      await installCommand(pluginName, options);
      break;
    }

    case 'list':
    case 'ls': {
      await listCommand(options);
      break;
    }

    case 'help':
      printHelp();
      break;

    default:
      console.error(`Unknown subcommand: ${subcommand}`);
      printHelp();
      process.exit(1);
  }
}

function printHelp() {
  console.log(`
Foliko Plugin Manager - Publish and install plugins to/from Git

Usage: foliko plugin <command> [options]

Commands:
  list, ls              List available plugins from repository
  publish <name>        Publish a plugin to the repository
  install <name>        Install a plugin from the repository

Options:
  --repo <url>          Specify repository URL (default: ${DEFAULT_REPO})

Environment Variables:
  FOLIKO_PLUGIN_REPO    Default repository URL

Examples:
  foliko plugin list
  foliko plugin publish my-plugin
  foliko plugin install my-plugin
  foliko plugin install other-plugin --repo https://github.com/user/other-plugins.git
`);
}

module.exports = { pluginCommand };
