#!/usr/bin/env node
/**
 * Schema Validation Script
 *
 * Validates JSON-LD structured data on all pages
 * Checks for common issues and provides recommendations
 *
 * Usage: node scripts/validate-schema.js
 */

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

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

const COLORS = {
  reset: '\x1b[0m',
  red: '\x1b[31m',
  green: '\x1b[32m',
  yellow: '\x1b[33m',
  blue: '\x1b[34m',
  cyan: '\x1b[36m',
};

const log = {
  success: (msg) => console.log(`${COLORS.green}✓${COLORS.reset} ${msg}`),
  error: (msg) => console.log(`${COLORS.red}✗${COLORS.reset} ${msg}`),
  warning: (msg) => console.log(`${COLORS.yellow}⚠${COLORS.reset} ${msg}`),
  info: (msg) => console.log(`${COLORS.blue}ℹ${COLORS.reset} ${msg}`),
  section: (msg) => console.log(`\n${COLORS.cyan}${msg}${COLORS.reset}\n`),
};

/**
 * Extract JSON-LD scripts from HTML
 */
function extractJsonLd(html) {
  const dom = new JSDOM(html);
  const scripts = dom.window.document.querySelectorAll('script[type="application/ld+json"]');
  return Array.from(scripts).map(script => {
    try {
      return JSON.parse(script.textContent);
    } catch (e) {
      log.error(`Failed to parse JSON-LD: ${e.message}`);
      return null;
    }
  }).filter(Boolean);
}

/**
 * Validate required fields for each schema type
 */
function validateSchema(schema) {
  const issues = [];
  const warnings = [];

  if (!schema['@context']) {
    issues.push('Missing @context');
  }

  if (!schema['@type']) {
    issues.push('Missing @type');
  }

  const type = schema['@type'];

  // Validate based on type
  switch (type) {
    case 'Organization':
      if (!schema.name) issues.push('Organization: Missing name');
      if (!schema.url) issues.push('Organization: Missing url');
      if (!schema.logo) warnings.push('Organization: Consider adding logo');
      if (!schema.contactPoint) warnings.push('Organization: Consider adding contactPoint');
      break;

    case 'BlogPosting':
      if (!schema.headline) issues.push('BlogPosting: Missing headline');
      if (!schema.author) issues.push('BlogPosting: Missing author');
      if (!schema.datePublished) issues.push('BlogPosting: Missing datePublished');
      if (!schema.publisher) issues.push('BlogPosting: Missing publisher');
      if (!schema.image) warnings.push('BlogPosting: Consider adding image');
      break;

    case 'BreadcrumbList':
      if (!schema.itemListElement || !Array.isArray(schema.itemListElement)) {
        issues.push('BreadcrumbList: Missing or invalid itemListElement');
      } else {
        schema.itemListElement.forEach((item, idx) => {
          if (!item.position) issues.push(`BreadcrumbList: Item ${idx} missing position`);
          if (!item.name) issues.push(`BreadcrumbList: Item ${idx} missing name`);
          if (!item.item) issues.push(`BreadcrumbList: Item ${idx} missing item URL`);
        });
      }
      break;

    case 'WebPage':
      if (!schema.name) issues.push('WebPage: Missing name');
      if (!schema.url) issues.push('WebPage: Missing url');
      if (!schema.description) warnings.push('WebPage: Consider adding description');
      break;

    case 'FAQPage':
      if (!schema.mainEntity || !Array.isArray(schema.mainEntity)) {
        issues.push('FAQPage: Missing or invalid mainEntity');
      } else {
        schema.mainEntity.forEach((item, idx) => {
          if (item['@type'] !== 'Question') {
            issues.push(`FAQPage: Item ${idx} should be type Question`);
          }
          if (!item.name) issues.push(`FAQPage: Question ${idx} missing name`);
          if (!item.acceptedAnswer) {
            issues.push(`FAQPage: Question ${idx} missing acceptedAnswer`);
          }
        });
      }
      break;

    case 'Service':
      if (!schema.name) issues.push('Service: Missing name');
      if (!schema.description) issues.push('Service: Missing description');
      if (!schema.provider) warnings.push('Service: Consider adding provider');
      break;

    case 'WebSite':
      if (!schema.name) issues.push('WebSite: Missing name');
      if (!schema.url) issues.push('WebSite: Missing url');
      if (!schema.potentialAction) warnings.push('WebSite: Consider adding search action');
      break;
  }

  return { issues, warnings };
}

/**
 * Validate Open Graph tags
 */
function validateOpenGraph(html) {
  const dom = new JSDOM(html);
  const doc = dom.window.document;
  const issues = [];
  const warnings = [];

  const requiredOgTags = ['og:title', 'og:description', 'og:image', 'og:url', 'og:type'];

  requiredOgTags.forEach(tag => {
    const meta = doc.querySelector(`meta[property="${tag}"]`);
    if (!meta) {
      issues.push(`Missing required Open Graph tag: ${tag}`);
    }
  });

  const ogImage = doc.querySelector('meta[property="og:image"]');
  if (ogImage) {
    const imageUrl = ogImage.getAttribute('content');
    if (!imageUrl.startsWith('http')) {
      warnings.push('og:image should be an absolute URL');
    }
    if (!doc.querySelector('meta[property="og:image:width"]')) {
      warnings.push('Consider adding og:image:width');
    }
    if (!doc.querySelector('meta[property="og:image:height"]')) {
      warnings.push('Consider adding og:image:height');
    }
  }

  return { issues, warnings };
}

/**
 * Validate Twitter Card tags
 */
function validateTwitterCard(html) {
  const dom = new JSDOM(html);
  const doc = dom.window.document;
  const issues = [];
  const warnings = [];

  const requiredTwitterTags = ['twitter:card', 'twitter:title', 'twitter:description', 'twitter:image'];

  requiredTwitterTags.forEach(tag => {
    const meta = doc.querySelector(`meta[name="${tag}"]`);
    if (!meta) {
      issues.push(`Missing required Twitter Card tag: ${tag}`);
    }
  });

  const twitterCard = doc.querySelector('meta[name="twitter:card"]');
  if (twitterCard && twitterCard.getAttribute('content') === 'summary_large_image') {
    const twitterImage = doc.querySelector('meta[name="twitter:image"]');
    if (twitterImage) {
      const imageUrl = twitterImage.getAttribute('content');
      if (!imageUrl.startsWith('http')) {
        warnings.push('twitter:image should be an absolute URL');
      }
    }
  }

  return { issues, warnings };
}

/**
 * Main validation function
 */
async function validatePage(filePath, pageName) {
  log.section(`Validating: ${pageName}`);

  try {
    const html = fs.readFileSync(filePath, 'utf-8');

    // Extract and validate JSON-LD
    const schemas = extractJsonLd(html);

    if (schemas.length === 0) {
      log.warning('No JSON-LD structured data found');
    } else {
      log.info(`Found ${schemas.length} JSON-LD schema(s)`);

      schemas.forEach((schema, idx) => {
        console.log(`\n  Schema ${idx + 1}: ${schema['@type'] || 'Unknown'}`);
        const { issues, warnings } = validateSchema(schema);

        if (issues.length === 0) {
          log.success('No critical issues');
        } else {
          issues.forEach(issue => log.error(`  ${issue}`));
        }

        if (warnings.length > 0) {
          warnings.forEach(warning => log.warning(`  ${warning}`));
        }
      });
    }

    // Validate Open Graph
    console.log('\n  Open Graph:');
    const ogValidation = validateOpenGraph(html);
    if (ogValidation.issues.length === 0) {
      log.success('All required Open Graph tags present');
    } else {
      ogValidation.issues.forEach(issue => log.error(`  ${issue}`));
    }
    if (ogValidation.warnings.length > 0) {
      ogValidation.warnings.forEach(warning => log.warning(`  ${warning}`));
    }

    // Validate Twitter Cards
    console.log('\n  Twitter Card:');
    const twitterValidation = validateTwitterCard(html);
    if (twitterValidation.issues.length === 0) {
      log.success('All required Twitter Card tags present');
    } else {
      twitterValidation.issues.forEach(issue => log.error(`  ${issue}`));
    }
    if (twitterValidation.warnings.length > 0) {
      twitterValidation.warnings.forEach(warning => log.warning(`  ${warning}`));
    }

    return {
      schemas: schemas.length,
      issues: ogValidation.issues.length + twitterValidation.issues.length,
      warnings: ogValidation.warnings.length + twitterValidation.warnings.length,
    };

  } catch (error) {
    log.error(`Failed to validate ${pageName}: ${error.message}`);
    return { schemas: 0, issues: 1, warnings: 0 };
  }
}

/**
 * Main execution
 */
async function main() {
  console.log('\n╔════════════════════════════════════════════════════════╗');
  console.log('║       Schema Validation for WorkRoot IT Solutions      ║');
  console.log('╚════════════════════════════════════════════════════════╝\n');

  const distDir = path.join(__dirname, '..', 'dist');

  if (!fs.existsSync(distDir)) {
    log.error('Build directory not found. Please run "npm run build" first.');
    process.exit(1);
  }

  // Pages to validate
  const pages = [
    { path: path.join(distDir, 'index.html'), name: 'Homepage' },
    { path: path.join(distDir, 'about', 'index.html'), name: 'About' },
    { path: path.join(distDir, 'services', 'index.html'), name: 'Services' },
    { path: path.join(distDir, 'contact', 'index.html'), name: 'Contact' },
    { path: path.join(distDir, 'blog', 'index.html'), name: 'Blog Index' },
  ];

  // Find a blog post to validate
  const blogDir = path.join(distDir, 'blog');
  if (fs.existsSync(blogDir)) {
    const blogPosts = fs.readdirSync(blogDir)
      .filter(file => fs.statSync(path.join(blogDir, file)).isDirectory());

    if (blogPosts.length > 0) {
      pages.push({
        path: path.join(blogDir, blogPosts[0], 'index.html'),
        name: `Blog Post (${blogPosts[0]})`
      });
    }
  }

  let totalSchemas = 0;
  let totalIssues = 0;
  let totalWarnings = 0;

  for (const page of pages) {
    if (fs.existsSync(page.path)) {
      const result = await validatePage(page.path, page.name);
      totalSchemas += result.schemas;
      totalIssues += result.issues;
      totalWarnings += result.warnings;
    } else {
      log.warning(`Page not found: ${page.name}`);
    }
  }

  // Summary
  log.section('Validation Summary');
  console.log(`Total schemas found: ${COLORS.cyan}${totalSchemas}${COLORS.reset}`);
  console.log(`Total issues: ${totalIssues > 0 ? COLORS.red : COLORS.green}${totalIssues}${COLORS.reset}`);
  console.log(`Total warnings: ${totalWarnings > 0 ? COLORS.yellow : COLORS.green}${totalWarnings}${COLORS.reset}`);

  if (totalIssues === 0) {
    log.success('\nAll validations passed! 🎉');
  } else {
    log.error('\nPlease fix the issues above before deployment.');
  }

  console.log('\n');
  process.exit(totalIssues > 0 ? 1 : 0);
}

main();
