#!/usr/bin/env node
import { readFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';

const distributionMode = process.argv.includes('--distribution');
const skipNpmCheck = process.argv.includes('--skip-npm') || process.env.SKIP_NPM_CHECK === 'true';

const __dirname = dirname(fileURLToPath(import.meta.url));
const serverDir = join(__dirname, '..');
const repoRoot = join(serverDir, '..');

const files = [
  { path: join(serverDir, 'package.json'), name: 'server/package.json' },
  { path: join(repoRoot, 'manifest.json'), name: 'manifest.json' },
  { path: join(repoRoot, '.claude-plugin', 'plugin.json'), name: '.claude-plugin/plugin.json' },
];

const readJson = (path) => JSON.parse(readFileSync(path, 'utf-8'));

const readJsonSafe = (path, name) => {
  try {
    return { content: readJson(path), error: null };
  } catch (err) {
    return { content: null, error: `${name}: ${err.message}` };
  }
};

const versions = files.map((f) => {
  const { content, error } = readJsonSafe(f.path, f.name);
  return {
    ...f,
    version: content?.version ?? null,
    error,
  };
});

const validVersions = versions.filter((v) => v.version);
const uniqueVersions = [...new Set(validVersions.map((v) => v.version))];

console.log('Version Check:');
versions.forEach((v) => {
  const status = v.error ? '❌ MISSING' : uniqueVersions.length === 1 ? '✅' : '⚠️';
  console.log(`  ${status} ${v.name}: ${v.version || v.error}`);
});

if (uniqueVersions.length > 1) {
  console.error('\n❌ Version mismatch detected!');
  console.error(`   Found versions: ${uniqueVersions.join(', ')}`);
  console.error('   All manifest files must have the same version.');
  process.exit(1);
}

if (uniqueVersions.length === 0) {
  console.error('\n❌ No valid versions found!');
  process.exit(1);
}

const coreVersion = uniqueVersions[0];

const releaseManifestPath = join(repoRoot, '.release-please-manifest.json');
try {
  const manifest = readJson(releaseManifestPath);
  const manifestVersion = manifest['.'] || manifest.server;
  if (manifestVersion && manifestVersion !== coreVersion) {
    console.error(`\n❌ Release manifest mismatch: ${manifestVersion} (expected ${coreVersion})`);
    process.exit(1);
  }
} catch (err) {
  console.error(`\n❌ Unable to read ${releaseManifestPath}: ${err.message}`);
  process.exit(1);
}

const changelogPath = join(repoRoot, 'CHANGELOG.md');
try {
  const content = readFileSync(changelogPath, 'utf-8');
  if (!content.includes(`## [${coreVersion}]`)) {
    console.error(`\n❌ Missing changelog entry for ${coreVersion} in CHANGELOG.md`);
    process.exit(1);
  }
} catch (err) {
  console.error(`\n❌ Unable to read ${changelogPath}: ${err.message}`);
  process.exit(1);
}

console.log(`\n✅ Local versions consistent: ${coreVersion}`);

const fetchJson = async (url) => {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`Request failed (${response.status} ${response.statusText})`);
  }
  return response.json();
};

const assertVersion = (label, actual) => {
  if (!actual) {
    throw new Error(`${label} missing version`);
  }
  if (actual !== coreVersion) {
    throw new Error(`${label} version ${actual} does not match ${coreVersion}`);
  }
};

const assertMarketplaceSource = (source) => {
  if (!source || source.source !== 'url') {
    throw new Error('Marketplace source must use url source');
  }
  if (source.url !== 'https://github.com/minipuft/claude-prompts-mcp.git') {
    throw new Error(`Marketplace source url mismatch: ${source.url}`);
  }
  if (source.ref !== 'dist') {
    throw new Error(`Marketplace source ref mismatch: ${source.ref}`);
  }
};

const distributionChecks = [
  {
    label: 'minipuft-plugins marketplace',
    url: 'https://raw.githubusercontent.com/minipuft/minipuft-plugins/main/.claude-plugin/marketplace.json',
    validate: (data) => {
      const entry = data.plugins?.find((plugin) => plugin.name === 'claude-prompts');
      if (!entry) {
        throw new Error('Marketplace entry for claude-prompts missing');
      }
      assertVersion('Marketplace plugin', entry.version);
      assertMarketplaceSource(entry.source);
    },
  },
  {
    label: 'gemini-prompts gemini-extension.json',
    url: 'https://raw.githubusercontent.com/minipuft/gemini-prompts/main/gemini-extension.json',
    validate: (data) => assertVersion('Gemini extension', data.version),
  },
  {
    label: 'opencode-prompts dependency',
    url: 'https://raw.githubusercontent.com/minipuft/opencode-prompts/main/package.json',
    validate: (data) => {
      const dep = data.dependencies?.['claude-prompts'];
      if (!dep) {
        throw new Error('OpenCode package missing claude-prompts dependency');
      }
      // Check that the semver range covers the current version (^MAJOR.0.0)
      const majorMatch = dep.match(/\^(\d+)\./);
      if (!majorMatch) {
        throw new Error(`OpenCode dependency range unexpected format: ${dep}`);
      }
      const depMajor = parseInt(majorMatch[1], 10);
      const coreMajor = parseInt(coreVersion.split('.')[0], 10);
      if (depMajor !== coreMajor) {
        throw new Error(
          `OpenCode dependency ${dep} does not cover ${coreVersion} (major mismatch: ${depMajor} vs ${coreMajor})`
        );
      }
    },
  },
];

const npmCheck = async () => {
  if (skipNpmCheck) {
    return;
  }
  const data = await fetchJson('https://registry.npmjs.org/claude-prompts/latest');
  assertVersion('npm latest', data.version);
};

const runDistributionChecks = async () => {
  console.log('\nDistribution Check:');
  for (const check of distributionChecks) {
    try {
      const data = await fetchJson(check.url);
      check.validate(data);
      console.log(`  ✅ ${check.label}`);
    } catch (err) {
      console.error(`  ❌ ${check.label}: ${err.message}`);
      process.exit(1);
    }
  }

  try {
    await npmCheck();
    if (!skipNpmCheck) {
      console.log('  ✅ npm latest');
    }
  } catch (err) {
    console.error(`  ❌ npm latest: ${err.message}`);
    process.exit(1);
  }

  console.log(`\n✅ Distribution versions match ${coreVersion}`);
};

if (distributionMode) {
  await runDistributionChecks();
}
