#!/usr/bin/env tsx

/**
 * TimeSafari Asset Configuration Validator
 * Validates capacitor-assets configuration against schema and source files
 * Author: Matthew Raymer
 * 
 * Usage: tsx scripts/assets-validator.ts [config-path]
 */

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const PROJECT_ROOT = path.dirname(__dirname);

// TypeScript interfaces for validation
interface ValidationError {
  message: string;
}

interface AssetConfig {
  icon?: {
    source?: string;
    android?: {
      adaptive?: {
        foreground?: string;
        background?: string;
        monochrome?: string;
      };
    };
  };
  splash?: {
    source?: string;
    darkSource?: string;
  };
}

/**
 * Load and parse JSON file
 * @param filePath - Path to JSON file
 * @returns Parsed JSON object
 */
function loadJsonFile(filePath: string): AssetConfig {
  try {
    const content = fs.readFileSync(filePath, 'utf8');
    return JSON.parse(content);
  } catch (error) {
    throw new Error(`Failed to load ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
  }
}

/**
 * Validate configuration against schema
 * @param config - Configuration object to validate
 * @returns Array of validation errors
 */
function validateAgainstSchema(config: AssetConfig): ValidationError[] {
  const errors: ValidationError[] = [];

  // Basic structure validation
  if (!config.icon || !config.splash) {
    errors.push({ message: 'Configuration must contain both "icon" and "splash" sections' });
  }

  // Icon validation
  if (config.icon) {
    if (!config.icon.source) {
      errors.push({ message: 'Icon section must contain "source" field' });
    } else if (!/^resources\/.*\.(png|svg)$/.test(config.icon.source)) {
      errors.push({ message: 'Icon source must be a PNG or SVG file in resources/ directory' });
    }

    // Android adaptive icon validation
    if (config.icon.android?.adaptive) {
      const adaptive = config.icon.android.adaptive;
      if (!adaptive.foreground || !adaptive.background) {
        errors.push({ message: 'Android adaptive icon must have both foreground and background' });
      }
      if (adaptive.foreground && !/^resources\/.*\.(png|svg)$/.test(adaptive.foreground)) {
        errors.push({ message: 'Android adaptive foreground must be a PNG or SVG file in resources/ directory' });
      }
    }
  }

  // Splash validation
  if (config.splash) {
    if (!config.splash.source) {
      errors.push({ message: 'Splash section must contain "source" field' });
    } else if (!/^resources\/.*\.(png|svg)$/.test(config.splash.source)) {
      errors.push({ message: 'Splash source must be a PNG or SVG file in resources/ directory' });
    }

    if (config.splash.darkSource && !/^resources\/.*\.(png|svg)$/.test(config.splash.darkSource)) {
      errors.push({ message: 'Dark splash source must be a PNG or SVG file in resources/ directory' });
    }
  }

  return errors;
}

/**
 * Validate that source files exist
 * @param config - Configuration object
 * @returns Array of missing file errors
 */
function validateSourceFiles(config: AssetConfig): ValidationError[] {
  const errors: ValidationError[] = [];
  const requiredFiles = new Set<string>();

  // Collect all required source files
  if (config.icon?.source) requiredFiles.add(config.icon.source);
  if (config.icon?.android?.adaptive?.foreground) requiredFiles.add(config.icon.android.adaptive.foreground);
  if (config.icon?.android?.adaptive?.monochrome) requiredFiles.add(config.icon.android.adaptive.monochrome);
  if (config.splash?.source) requiredFiles.add(config.splash.source);
  if (config.splash?.darkSource) requiredFiles.add(config.splash.darkSource);

  // Check each file exists
  requiredFiles.forEach(file => {
    const filePath = path.join(PROJECT_ROOT, file);
    if (!fs.existsSync(filePath)) {
      errors.push({ message: `Source file not found: ${file}` });
    }
  });

  return errors;
}

/**
 * Validate target directories are writable
 * @param config - Configuration object
 * @returns Array of directory validation errors
 */
function validateTargetDirectories(config: AssetConfig): ValidationError[] {
  const errors: ValidationError[] = [];
  const targetDirs = new Set<string>();

  // Collect all target directories
  if (config.icon?.android?.target) targetDirs.add(config.icon.android.target);
  if (config.icon?.ios?.target) targetDirs.add(config.icon.ios.target);
  if (config.icon?.web?.target) targetDirs.add(config.icon.web.target);
  if (config.splash?.android?.target) targetDirs.add(config.splash.android.target);
  if (config.splash?.ios?.target) targetDirs.add(config.splash.ios.target);

  // Check each target directory
  targetDirs.forEach(dir => {
    const dirPath = path.join(PROJECT_ROOT, dir);
    const parentDir = path.dirname(dirPath);
    
    if (!fs.existsSync(parentDir)) {
      errors.push({ message: `Parent directory does not exist: ${parentDir}` });
    } else if (!fs.statSync(parentDir).isDirectory()) {
      errors.push({ message: `Parent path is not a directory: ${parentDir}` });
    }
  });

  return errors;
}

/**
 * Main validation function
 * @param configPath - Path to configuration file
 * @returns True if validation passes
 */
function validateConfiguration(configPath: string): boolean {
  console.log('🔍 Validating TimeSafari asset configuration...');
  console.log(`📁 Config file: ${configPath}`);
  console.log(`📁 Project root: ${PROJECT_ROOT}`);

  try {
    // Load configuration
    const config = loadJsonFile(configPath);
    console.log('✅ Configuration file loaded successfully');

    // Load schema
    const schemaPath = path.join(PROJECT_ROOT, 'config', 'assets', 'schema.json');
    const schema = loadJsonFile(schemaPath);
    console.log('✅ Schema file loaded successfully');

    // Perform validations
    const schemaErrors = validateAgainstSchema(config);
    const fileErrors = validateSourceFiles(config);
    const dirErrors = validateTargetDirectories(config);

    // Report results
    const allErrors = [...schemaErrors, ...fileErrors, ...dirErrors];

    if (allErrors.length === 0) {
      console.log('🎉 All validations passed successfully!');
      console.log('');
      console.log('📋 Configuration summary:');
      console.log(`   Icon source: ${config.icon?.source || 'NOT SET'}`);
      console.log(`   Splash source: ${config.splash?.source || 'NOT SET'}`);
      console.log(`   Dark splash: ${config.splash?.darkSource || 'NOT SET'}`);
      console.log(`   Android adaptive: ${config.icon?.android?.adaptive ? 'ENABLED' : 'DISABLED'}`);
      console.log(`   iOS LaunchScreen: ${config.splash?.ios?.useStoryBoard ? 'ENABLED' : 'DISABLED'}`);
      return true;
    } else {
      console.error('❌ Validation failed with the following errors:');
      allErrors.forEach((error, index) => {
        console.error(`   ${index + 1}. ${error.message}`);
      });
      return false;
    }

  } catch (error) {
    console.error('❌ Validation failed:', error instanceof Error ? error.message : String(error));
    return false;
  }
}

/**
 * Main execution function
 */
function main(): void {
  const configPath = process.argv[2] || path.join(PROJECT_ROOT, 'capacitor-assets.config.json');
  
  if (!fs.existsSync(configPath)) {
    console.error(`❌ Configuration file not found: ${configPath}`);
    console.log('');
    console.log('💡 Available options:');
    console.log('   - Use default: capacitor-assets.config.json');
    console.log('   - Specify path: tsx scripts/assets-validator.ts path/to/config.json');
    console.log('   - Generate config: npm run assets:config');
    process.exit(1);
  }

  const success = validateConfiguration(configPath);
  process.exit(success ? 0 : 1);
}

// Run if called directly
if (import.meta.url === `file://${process.argv[1]}`) {
  main();
}

export { validateConfiguration, validateAgainstSchema, validateSourceFiles, validateTargetDirectories, AssetConfig };
