#!/usr/bin/env node
/**
 * Build a Divi Marketplace–compliant zip of PressConduit.
 *
 * HOW IT WORKS
 * ------------
 * The source uses a distribution-mode flag (see pressconduit.php:
 * pcd_pc_is_direct_build()). The normal relay build ships NO build-distribution.php
 * and defaults to 'direct', so licensing + self-updates load as usual. This
 * script produces the Marketplace package by:
 *
 *   1. Writing build-distribution.php with PCD_PC_DISTRIBUTION_MODE='marketplace',
 *      which makes pcd_pc_is_direct_build() false — the plugin then never loads,
 *      hooks, or renders the licensing/update code.
 *   2. Physically excluding the now-unused licensing + updater class files, so a
 *      line-by-line audit sees no custom-update or in-plugin-licensing code at all
 *      (Divi Marketplace forbids both).
 *   3. Verifying the GPLv2 license.txt (shipped from the source root) is present.
 *   4. Dropping internal dev files (bin/, docs/, *-SPEC.md).
 *
 * RESIDUAL AUDIT RISK (NOT auto-fixable — owner decision to proceed):
 *   The plugin still requires the external PressConduit relay + a customer's AI
 *   to function, which rubs against "your products must function with Divi and
 *   WordPress alone." This script cannot remove that without gutting the product.
 *
 * OUTPUT
 *   ../pressconduit-marketplace-<version>.zip   (top-level folder: pressconduit/)
 *
 * USAGE
 *   node bin/build-marketplace.mjs
 */
import {
	cpSync, rmSync, readFileSync, writeFileSync, existsSync, mkdirSync,
} from 'node:fs';
import { join, relative, dirname, sep } from 'node:path';
import { fileURLToPath } from 'node:url';
import { execSync } from 'node:child_process';

const __dirname = dirname( fileURLToPath( import.meta.url ) );
const PLUGIN_ROOT = join( __dirname, '..' );           // .../pressconduit
const REPO_ROOT   = join( PLUGIN_ROOT, '..' );          // .../Desktop/test
const STAGING     = join( REPO_ROOT, '.pc-marketplace-build' );
const STAGE_DIR   = join( STAGING, 'pressconduit' );    // zip needs this top folder

// Paths (relative to the plugin root) that must NOT ship to the Marketplace.
const EXCLUDE = new Set( [
	'bin',                                       // build tooling — internal
	'docs',                                      // dev notes — internal
	'PRICING-LICENSING-SPEC.md',                 // internal spec
	'includes/class-pcd-pc-updater.php',         // FORBIDDEN: self-update from own API
	'includes/class-pcd-pc-license.php',         // FORBIDDEN: in-plugin licensing system
	'build-distribution.php',                    // we write a fresh marketplace one below
	'.git',
	'node_modules',
] );

function isExcluded( absSrc ) {
	const rel = relative( PLUGIN_ROOT, absSrc );
	if ( rel === '' ) return false;              // the root itself
	const top = rel.split( sep )[ 0 ];
	if ( EXCLUDE.has( rel ) || EXCLUDE.has( top ) ) return true;
	if ( rel.endsWith( '.zip' ) ) return true;
	if ( rel.endsWith( '.DS_Store' ) ) return true;
	return false;
}

// --- read the version straight from the plugin header constant ---------------
const mainPhpSrc = readFileSync( join( PLUGIN_ROOT, 'pressconduit.php' ), 'utf8' );
const versionMatch = mainPhpSrc.match( /define\(\s*'PCD_PC_VERSION',\s*'([^']+)'\s*\)/ );
if ( ! versionMatch ) {
	console.error( 'Could not find PCD_PC_VERSION in pressconduit.php' );
	process.exit( 1 );
}
const VERSION = versionMatch[ 1 ];
const OUT_ZIP = join( REPO_ROOT, `pressconduit-marketplace-${ VERSION }.zip` );

// --- guard: the source MUST carry the distribution-mode gating, or disabling
//     licensing/updates by flag won't actually work and we'd ship a broken/
//     non-compliant package. Fail loudly rather than silently. ----------------
if ( ! mainPhpSrc.includes( 'pcd_pc_is_direct_build' ) ) {
	console.error( 'FAIL: pressconduit.php has no distribution-mode gating (pcd_pc_is_direct_build). Aborting.' );
	process.exit( 1 );
}

// --- fresh staging -----------------------------------------------------------
rmSync( STAGING, { recursive: true, force: true } );
mkdirSync( STAGE_DIR, { recursive: true } );
cpSync( PLUGIN_ROOT, STAGE_DIR, { recursive: true, filter: ( src ) => ! isExcluded( src ) } );

// --- write the marketplace distribution marker -------------------------------
const distPhp = `<?php
/**
 * Divi Marketplace build marker.
 *
 * Sets distribution mode to 'marketplace', which disables PressConduit's
 * in-plugin licensing and self-update systems (both forbidden by the Divi
 * Marketplace). The normal relay/direct build does NOT contain this file and
 * defaults to 'direct'. Do not ship this file outside the Marketplace package.
 */
if ( ! defined( 'ABSPATH' ) ) {
\texit;
}
if ( ! defined( 'PCD_PC_DISTRIBUTION_MODE' ) ) {
\tdefine( 'PCD_PC_DISTRIBUTION_MODE', 'marketplace' );
}
`;
writeFileSync( join( STAGE_DIR, 'build-distribution.php' ), distPhp );

// --- verify the GPLv2 license.txt carried in from the source root ------------
// license.txt lives in the plugin root (single source of truth) and is copied
// with the tree above, so every build ships the same file. Just guard that it
// landed and contains the full GPL text, so we never ship a package without it.
const stagedLicense = join( STAGE_DIR, 'license.txt' );
if ( ! existsSync( stagedLicense ) ) {
	console.error( 'FAIL: license.txt is missing from the source root. Aborting.' );
	process.exit( 1 );
}
if ( ! readFileSync( stagedLicense, 'utf8' ).includes( 'GNU GENERAL PUBLIC LICENSE' ) ) {
	console.error( 'FAIL: license.txt does not contain the full GPL text. Aborting.' );
	process.exit( 1 );
}

// --- keep readme Stable tag honest -------------------------------------------
const stagedReadme = join( STAGE_DIR, 'readme.txt' );
if ( existsSync( stagedReadme ) ) {
	let readme = readFileSync( stagedReadme, 'utf8' );
	readme = readme.replace( /Stable tag:\s*.*/i, `Stable tag: ${ VERSION }` );
	writeFileSync( stagedReadme, readme );
}

// --- safety net: forbidden files must be absent ------------------------------
for ( const forbidden of [
	'includes/class-pcd-pc-updater.php',
	'includes/class-pcd-pc-license.php',
] ) {
	if ( existsSync( join( STAGE_DIR, forbidden ) ) ) {
		console.error( `FAIL: forbidden file leaked into the package: ${ forbidden }` );
		process.exit( 1 );
	}
}

// --- zip it ------------------------------------------------------------------
rmSync( OUT_ZIP, { force: true } );
execSync( `zip -rq "${ OUT_ZIP }" pressconduit -x "*.DS_Store"`, { cwd: STAGING, stdio: 'inherit' } );

// --- clean up staging --------------------------------------------------------
rmSync( STAGING, { recursive: true, force: true } );

console.log( '' );
console.log( `Built marketplace package: ${ OUT_ZIP }` );
console.log( `Version: ${ VERSION }` );
console.log( 'Mode: marketplace (licensing + self-update disabled via build-distribution.php and excluded from package)' );
console.log( 'Added: build-distribution.php (license.txt ships from the source root)' );
console.log( 'Excluded: updater + license classes, bin/, docs/, *-SPEC.md' );
console.log( 'Reminder: relay dependency remains — see header note about audit risk.' );
