#!/usr/bin/env node

const { execSync } = require('node:child_process');
const { existsSync, mkdirSync, writeFileSync, readFileSync } = require('node:fs');
const path = require('node:path');

const { argv } = require('node:process');
const inputIdx = argv.indexOf('--input');
const INPUT_FILE = inputIdx > -1 ? argv[inputIdx + 1] : null;
const POSTPROCESS_ONLY = !!INPUT_FILE;

// __dirname is available in CommonJS by default

/**
 * Generate 3rd party licenses for frontend dependencies
 * This script creates a JSON file similar to the Java backend's 3rdPartyLicenses.json
 */

const OUTPUT_FILE = path.join(__dirname, '..', 'src', 'assets', '3rdPartyLicenses.json');
const PACKAGE_JSON = path.join(__dirname, '..', 'package.json');

// Ensure the output directory exists
const outputDir = path.dirname(OUTPUT_FILE);
if (!existsSync(outputDir)) {
    mkdirSync(outputDir, { recursive: true });
}

console.log('🔍 Generating frontend license report...');

try {
    // Safety guard: don't run this script on fork PRs (workflow setzt PR_IS_FORK)
    if (process.env.PR_IS_FORK === 'true' && !POSTPROCESS_ONLY) {
        console.error('Fork PR detected: only --input (postprocess-only) mode is allowed.');
        process.exit(2);
    }

    let licenseData;
    // Generate license report using pinned license-checker; disable lifecycle scripts
    if (POSTPROCESS_ONLY) {
      if (!INPUT_FILE || !existsSync(INPUT_FILE)) {
        console.error('❌ --input file missing or not found');
        process.exit(1);
      }
      licenseData = JSON.parse(readFileSync(INPUT_FILE, 'utf8'));
    } else {
      const licenseReport = execSync(
          // 'npx --yes license-checker@25.0.1 --production --json',
          'npx --yes license-report --only=prod --output=json',
          {
              encoding: 'utf8',
              cwd: path.dirname(PACKAGE_JSON),
              env: { ...process.env, NPM_CONFIG_IGNORE_SCRIPTS: 'true' }
          }
      );
      try {
          licenseData = JSON.parse(licenseReport);
      } catch (parseError) {
          console.error('❌ Failed to parse license data:', parseError.message);
          console.error('Raw output:', licenseReport.substring(0, 500) + '...');
          process.exit(1);
      }
    }

    if (!Array.isArray(licenseData)) {
        console.error('❌ Invalid license data structure');
        process.exit(1);
    }

    // Convert license-checker format to array
    const licenseArray = licenseData.map(dep => {
        let licenseType = dep.licenseType;

        // Handle missing or null licenses
        if (!licenseType || licenseType === null || licenseType === undefined) {
            licenseType = 'Unknown';
        }

        // Handle empty string licenses
        if (licenseType === '') {
            licenseType = 'Unknown';
        }

        // Handle array licenses (rare but possible)
        if (Array.isArray(licenseType)) {
            licenseType = licenseType.join(' AND ');
        }

        // Handle object licenses (fallback)
        if (typeof licenseType === 'object' && licenseType !== null) {
            licenseType = 'Unknown';
        }

        if ( "posthog-js" === dep.name && licenseType.startsWith("SEE LICENSE IN LICENSE")) {
            licenseType = "SEE LICENSE IN LICENSE https://github.com/PostHog/posthog-js/blob/main/LICENSE";
        }

        return {
            name: dep.name,
            version: dep.installedVersion || dep.definedVersion || dep.remoteVersion || 'unknown',
            licenseType: licenseType,
            repository: dep.link,
            url: dep.link,
            link: dep.link
        };
    });

    // Transform to match Java backend format
    const transformedData = {
        dependencies: licenseArray.map(dep => {
            const licenseType = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : (dep.licenseType || 'Unknown');
            const licenseUrl = dep.link || getLicenseUrl(licenseType);

            return {
                moduleName: dep.name,
                moduleUrl: dep.repository || dep.url || `https://www.npmjs.com/package/${dep.name}`,
                moduleVersion: dep.version,
                moduleLicense: licenseType,
                moduleLicenseUrl: licenseUrl
            };
        })
    };

    // Log summary of license types found
    const licenseSummary = licenseArray.reduce((acc, dep) => {
        const license = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : (dep.licenseType || 'Unknown');
        acc[license] = (acc[license] || 0) + 1;
        return acc;
    }, {});

    console.log('📊 License types found:');
    Object.entries(licenseSummary).forEach(([license, count]) => {
        console.log(`   ${license}: ${count} packages`);
    });

    // Log any complex or unusual license formats for debugging
    const complexLicenses = licenseArray.filter(dep =>
        dep.licenseType && (
            dep.licenseType.includes('AND') ||
            dep.licenseType.includes('OR') ||
            dep.licenseType === 'Unknown' ||
            dep.licenseType.includes('SEE LICENSE')
        )
    );

    if (complexLicenses.length > 0) {
        console.log('\n🔍 Complex/Edge case licenses detected:');
        complexLicenses.forEach(dep => {
            console.log(`   ${dep.name}@${dep.version}: "${dep.licenseType}"`);
        });
    }

    // Check for potentially problematic licenses
    const problematicLicenses = checkLicenseCompatibility(licenseSummary, licenseArray);
    if (problematicLicenses.length > 0) {
        console.log('\n⚠️  License compatibility warnings:');
        problematicLicenses.forEach(warning => {
            console.log(`   ${warning.message}`);
        });

        // Write license warnings to a separate file for CI/CD
        const warningsFile = path.join(__dirname, '..', 'src', 'assets', 'license-warnings.json');
        writeFileSync(warningsFile, JSON.stringify({
            warnings: problematicLicenses,
            generated: new Date().toISOString()
        }, null, 2));
        console.log(`⚠️  License warnings saved to: ${warningsFile}`);
    } else {
        console.log('\n✅ All licenses appear to be corporate-friendly');
    }

    // Write to file
    writeFileSync(OUTPUT_FILE, JSON.stringify(transformedData, null, 4));

    console.log(`✅ License report generated successfully!`);
    console.log(`📄 Found ${transformedData.dependencies.length} dependencies`);
    console.log(`💾 Saved to: ${OUTPUT_FILE}`);

} catch (error) {
    console.error('❌ Error generating license report:', error.message);
    process.exit(1);
}

/**
 * Get standard license URLs for common licenses
 */
function getLicenseUrl(licenseType) {
    if (!licenseType || licenseType === 'Unknown') return '';

    const licenseUrls = {
        'MIT': 'https://opensource.org/licenses/MIT',
        'MIT*': 'https://opensource.org/licenses/MIT',
        'Apache-2.0': 'https://www.apache.org/licenses/LICENSE-2.0',
        'Apache License 2.0': 'https://www.apache.org/licenses/LICENSE-2.0',
        'BSD-3-Clause': 'https://opensource.org/licenses/BSD-3-Clause',
        'BSD-2-Clause': 'https://opensource.org/licenses/BSD-2-Clause',
        'BSD': 'https://opensource.org/licenses/BSD-3-Clause',
        'GPL-3.0': 'https://www.gnu.org/licenses/gpl-3.0.html',
        'GPL-2.0': 'https://www.gnu.org/licenses/gpl-2.0.html',
        'LGPL-2.1': 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html',
        'LGPL-3.0': 'https://www.gnu.org/licenses/lgpl-3.0.html',
        'ISC': 'https://opensource.org/licenses/ISC',
        'CC0-1.0': 'https://creativecommons.org/publicdomain/zero/1.0/',
        'Unlicense': 'https://unlicense.org/',
        'MPL-2.0': 'https://www.mozilla.org/en-US/MPL/2.0/',
        'WTFPL': 'http://www.wtfpl.net/',
        'Zlib': 'https://opensource.org/licenses/Zlib',
        'Artistic-2.0': 'https://opensource.org/licenses/Artistic-2.0',
        'EPL-1.0': 'https://www.eclipse.org/legal/epl-v10.html',
        'EPL-2.0': 'https://www.eclipse.org/legal/epl-2.0/',
        'CDDL-1.0': 'https://opensource.org/licenses/CDDL-1.0',
        'Ruby': 'https://www.ruby-lang.org/en/about/license.txt',
        'Python-2.0': 'https://www.python.org/download/releases/2.0/license/',
        'Public Domain': 'https://creativecommons.org/publicdomain/zero/1.0/',
        'UNLICENSED': ''
    };

    // Try exact match first
    if (licenseUrls[licenseType]) {
        return licenseUrls[licenseType];
    }

    // Try case-insensitive match
    const lowerType = licenseType.toLowerCase();
    for (const [key, url] of Object.entries(licenseUrls)) {
        if (key.toLowerCase() === lowerType) {
            return url;
        }
    }

    // Handle complex SPDX expressions like "(MIT AND Zlib)" or "(MIT OR CC0-1.0)"
    if (licenseType.includes('AND') || licenseType.includes('OR')) {
        // Extract the first license from compound expressions for URL
        const match = licenseType.match(/\(?\s*([A-Za-z0-9\-.]+)/);
        if (match && licenseUrls[match[1]]) {
            return licenseUrls[match[1]];
        }
    }

    // For non-standard licenses, return empty string (will use package link if available)
    return '';
}

/**
 * Check for potentially problematic licenses that may not be MIT/corporate compatible
 */
function checkLicenseCompatibility(licenseSummary, licenseArray) {
    const warnings = [];

    // Define problematic license patterns
    const problematicLicenses = {
        // Copyleft licenses
        'GPL-2.0': 'Strong copyleft license - requires derivative works to be GPL',
        'GPL-3.0': 'Strong copyleft license - requires derivative works to be GPL',
        'LGPL-2.1': 'Weak copyleft license - may require source disclosure for modifications',
        'LGPL-3.0': 'Weak copyleft license - may require source disclosure for modifications',
        'AGPL-3.0': 'Network copyleft license - requires source disclosure for network use',
        'AGPL-1.0': 'Network copyleft license - requires source disclosure for network use',

        // Other potentially problematic licenses
        'WTFPL': 'Potentially problematic license - legal uncertainty',
        'CC-BY-SA-4.0': 'ShareAlike license - requires derivative works to use same license',
        'CC-BY-SA-3.0': 'ShareAlike license - requires derivative works to use same license',
        'CC-BY-NC-4.0': 'Non-commercial license - prohibits commercial use',
        'CC-BY-NC-3.0': 'Non-commercial license - prohibits commercial use',
        'OSL-3.0': 'Copyleft license - requires derivative works to be OSL',
        'EPL-1.0': 'Weak copyleft license - may require source disclosure',
        'EPL-2.0': 'Weak copyleft license - may require source disclosure',
        'CDDL-1.0': 'Weak copyleft license - may require source disclosure',
        'CDDL-1.1': 'Weak copyleft license - may require source disclosure',
        'CPL-1.0': 'Weak copyleft license - may require source disclosure',
        'MPL-1.1': 'Weak copyleft license - may require source disclosure',
        'EUPL-1.1': 'Copyleft license - requires derivative works to be EUPL',
        'EUPL-1.2': 'Copyleft license - requires derivative works to be EUPL',
        'UNLICENSED': 'No license specified - usage rights unclear',
        'Unknown': 'License not detected - manual review required'
    };

    // Known good licenses (no warnings needed)
    const goodLicenses = new Set([
        'MIT', 'MIT*', 'Apache-2.0', 'Apache License 2.0', 'BSD-2-Clause', 'BSD-3-Clause', 'BSD',
        'ISC', 'CC0-1.0', 'Public Domain', 'Unlicense', '0BSD', 'BlueOak-1.0.0',
        'Zlib', 'Artistic-2.0', 'Python-2.0', 'Ruby', 'MPL-2.0', 'CC-BY-4.0',
        'SEE LICENSE IN https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/proprietary/LICENSE',
        'SEE LICENSE IN LICENSE https://github.com/PostHog/posthog-js/blob/main/LICENSE'
    ]);

    // Helper function to normalize license names for comparison
    function normalizeLicense(license) {
        return license
            .replace(/-or-later$/, '') // Remove -or-later suffix
            .replace(/\+$/, '') // Remove + suffix
            .trim();
    }

    // Check each license type
    Object.entries(licenseSummary).forEach(([license, count]) => {
        // Skip known good licenses
        if (goodLicenses.has(license)) {
            return;
        }

        // Check if this license only affects our own packages
        const affectedPackages = licenseArray.filter(dep => {
            const depLicense = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : dep.licenseType;
            return depLicense === license;
        });

        const isOnlyOurPackages = affectedPackages.every(dep =>
            dep.name === 'frontend' ||
            dep.name.toLowerCase().includes('stirling-pdf') ||
            dep.name.toLowerCase().includes('stirling_pdf') ||
            dep.name.toLowerCase().includes('stirlingpdf')
        );

        if (isOnlyOurPackages && (license === 'UNLICENSED' || license.startsWith('SEE LICENSE IN'))) {
            return; // Skip warnings for our own Stirling-PDF packages
        }

        // Check for compound licenses like "(MIT AND Zlib)" or "(MIT OR CC0-1.0)"
        if (license.includes('AND') || license.includes('OR')) {
            // For OR licenses, check if there's at least one acceptable license option
            if (license.includes('OR')) {
                // Extract license components from OR expression
                const orComponents = license
                    .replace(/[()]/g, '') // Remove parentheses
                    .split(' OR ')
                    .map(component => component.trim());

                // Check if any component is in the goodLicenses set (with normalization)
                const hasGoodLicense = orComponents.some(component => {
                    const normalized = normalizeLicense(component);
                    return goodLicenses.has(component) || goodLicenses.has(normalized);
                });

                if (hasGoodLicense) {
                    return; // Skip warning - can use the good license option
                }
            }

            // For AND licenses or OR licenses with no good options, check for problematic components
            const hasProblematicComponent = Object.keys(problematicLicenses).some(problematic =>
                license.includes(problematic)
            );

            if (hasProblematicComponent) {
                const affectedPackages = licenseArray
                    .filter(dep => {
                        const depLicense = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : dep.licenseType;
                        return depLicense === license;
                    })
                    .map(dep => ({
                        name: dep.name,
                        version: dep.version,
                        url: dep.repository || dep.url || `https://www.npmjs.com/package/${dep.name}`
                    }));

                const licenseType = license.includes('AND') ? 'AND' : 'OR';
                const reason = licenseType === 'AND'
                    ? 'Compound license with AND requirement - all components must be compatible'
                    : 'Compound license with potentially problematic components and no good fallback options';

                warnings.push({
                    message: `📋 This PR contains ${count} package${count > 1 ? 's' : ''} with compound license "${license}" - manual review recommended`,
                    licenseType: license,
                    licenseUrl: '',
                    reason: reason,
                    packageCount: count,
                    affectedDependencies: affectedPackages
                });
            }
            return;
        }

        // Check for exact matches with problematic licenses
        if (problematicLicenses[license]) {
            const affectedPackages = licenseArray
                .filter(dep => {
                    const depLicense = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : dep.licenseType;
                    return depLicense === license;
                })
                .map(dep => ({
                    name: dep.name,
                    version: dep.version,
                    url: dep.repository || dep.url || `https://www.npmjs.com/package/${dep.name}`
                }));

            const packageList = affectedPackages.map(pkg => pkg.name).slice(0, 5).join(', ') + (affectedPackages.length > 5 ? `, and ${affectedPackages.length - 5} more` : '');
            const licenseUrl = getLicenseUrl(license) || 'https://opensource.org/licenses';

            warnings.push({
                message: `⚠️  This PR contains ${count} package${count > 1 ? 's' : ''} with license type [${license}](${licenseUrl}) - ${problematicLicenses[license]}. Affected packages: ${packageList}`,
                licenseType: license,
                licenseUrl: licenseUrl,
                reason: problematicLicenses[license],
                packageCount: count,
                affectedDependencies: affectedPackages
            });
        } else {
            // Unknown license type - flag for manual review
            const affectedPackages = licenseArray
                .filter(dep => {
                    const depLicense = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : dep.licenseType;
                    return depLicense === license;
                })
                .map(dep => ({
                    name: dep.name,
                    version: dep.version,
                    url: dep.repository || dep.url || `https://www.npmjs.com/package/${dep.name}`
                }));

            warnings.push({
                message: `❓ This PR contains ${count} package${count > 1 ? 's' : ''} with unknown license type "${license}" - manual review required`,
                licenseType: license,
                licenseUrl: '',
                reason: 'Unknown license type',
                packageCount: count,
                affectedDependencies: affectedPackages
            });
        }
    });

    return warnings;
}
