/**
 * Sync Failure Analysis Script
 * Query and analyze sync_history for failures and patterns
 * Run with: npx tsx scripts/analyze-sync-failures.ts [options]
 */

import { config } from 'dotenv';
import { resolve } from 'path';
import postgresClient from '../lib/services/postgres-client';

// Load environment variables
config({ path: resolve(__dirname, '../.env.local') });

interface SyncHistoryRecord {
  id: number;
  entity_type: string;
  sync_type: string;
  status: string;
  started_at: Date;
  completed_at: Date | null;
  records_added: number;
  records_updated: number;
  records_deleted: number;
  error_message: string | null;
  triggered_by: string;
}

interface FailureSummary {
  entity_type: string;
  failure_count: number;
  last_failure: Date;
  common_errors: string[];
}

/**
 * Parse command line arguments
 */
function parseArgs(): {
  days: number;
  entity?: string;
  status?: string;
  showAll: boolean;
} {
  const args = process.argv.slice(2);
  const options = {
    days: 7,
    entity: undefined as string | undefined,
    status: undefined as string | undefined,
    showAll: false,
  };

  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    if (arg === '--days' || arg === '-d') {
      options.days = parseInt(args[++i]);
    } else if (arg === '--entity' || arg === '-e') {
      options.entity = args[++i];
    } else if (arg === '--status' || arg === '-s') {
      options.status = args[++i];
    } else if (arg === '--all' || arg === '-a') {
      options.showAll = true;
    } else if (arg === '--help' || arg === '-h') {
      console.log(`
Sync Failure Analysis Script

Usage: npx tsx scripts/analyze-sync-failures.ts [options]

Options:
  -d, --days <number>     Number of days to look back (default: 7)
  -e, --entity <type>     Filter by entity type
  -s, --status <status>   Filter by status (failed, completed, started)
  -a, --all               Show all records, not just failures
  -h, --help              Show this help message

Examples:
  # Show failures from last 7 days
  npx tsx scripts/analyze-sync-failures.ts

  # Show all syncs from yesterday
  npx tsx scripts/analyze-sync-failures.ts --days 1 --all

  # Show ticket sync failures from last 30 days
  npx tsx scripts/analyze-sync-failures.ts --days 30 --entity tickets

  # Show all completed syncs
  npx tsx scripts/analyze-sync-failures.ts --status completed --all
      `);
      process.exit(0);
    }
  }

  return options;
}

/**
 * Query sync history
 */
async function querySyncHistory(
  days: number,
  entity?: string,
  status?: string
): Promise<SyncHistoryRecord[]> {
  const params: any[] = [];
  let query = `
    SELECT 
      id,
      entity_type,
      sync_type,
      status,
      started_at,
      completed_at,
      records_added,
      records_updated,
      records_deleted,
      error_message,
      triggered_by
    FROM sync_history
    WHERE started_at >= NOW() - INTERVAL '${days} days'
  `;

  if (entity) {
    params.push(entity);
    query += ` AND entity_type = $${params.length}`;
  }

  if (status) {
    params.push(status);
    query += ` AND status = $${params.length}`;
  }

  query += ' ORDER BY started_at DESC';

  const result = await postgresClient.query<SyncHistoryRecord>(query, params);
  return result.rows;
}

/**
 * Get failure summary by entity
 */
async function getFailureSummary(days: number): Promise<FailureSummary[]> {
  const query = `
    SELECT 
      entity_type,
      COUNT(*) as failure_count,
      MAX(started_at) as last_failure,
      ARRAY_AGG(DISTINCT SUBSTRING(error_message, 1, 100)) as common_errors
    FROM sync_history
    WHERE status = 'failed'
      AND started_at >= NOW() - INTERVAL '${days} days'
    GROUP BY entity_type
    ORDER BY failure_count DESC, last_failure DESC
  `;

  const result = await postgresClient.query<any>(query);
  return result.rows.map(row => ({
    entity_type: row.entity_type,
    failure_count: parseInt(row.failure_count),
    last_failure: row.last_failure,
    common_errors: row.common_errors.filter((e: string | null) => e !== null),
  }));
}

/**
 * Categorize error message
 */
function categorizeError(errorMessage: string | null): string {
  if (!errorMessage) return 'UNKNOWN';
  
  if (errorMessage.includes('NETWORK_ERROR')) return 'NETWORK';
  if (errorMessage.includes('AUTH_ERROR')) return 'AUTH';
  if (errorMessage.includes('RATE_LIMIT_ERROR')) return 'RATE_LIMIT';
  if (errorMessage.includes('DATABASE_CONSTRAINT_ERROR')) return 'DB_CONSTRAINT';
  if (errorMessage.includes('DATABASE_ERROR')) return 'DATABASE';
  if (errorMessage.includes('API_ERROR')) return 'API';
  if (errorMessage.includes('MAPPING_ERROR')) return 'MAPPING';
  if (errorMessage.includes('VALIDATION_ERROR')) return 'VALIDATION';
  
  return 'OTHER';
}

/**
 * Format duration
 */
function formatDuration(startedAt: Date, completedAt: Date | null): string {
  if (!completedAt) return 'N/A';
  const duration = new Date(completedAt).getTime() - new Date(startedAt).getTime();
  const seconds = Math.floor(duration / 1000);
  const minutes = Math.floor(seconds / 60);
  
  if (minutes > 0) {
    return `${minutes}m ${seconds % 60}s`;
  }
  return `${seconds}s`;
}

/**
 * Main analysis function
 */
async function analyzeSyncFailures() {
  console.log('🔍 Sync Failure Analysis\n');
  console.log('═══════════════════════════════════════════════════════════\n');

  const options = parseArgs();

  try {
    // Test database connection
    const isConnected = await postgresClient.testConnection();
    if (!isConnected) {
      console.error('❌ Database connection failed');
      process.exit(1);
    }

    // Get sync history
    const records = await querySyncHistory(
      options.days,
      options.entity,
      options.status || (options.showAll ? undefined : 'failed')
    );

    console.log(`📊 Analysis Period: Last ${options.days} day(s)`);
    if (options.entity) {
      console.log(`🎯 Entity Filter: ${options.entity}`);
    }
    if (options.status) {
      console.log(`📌 Status Filter: ${options.status}`);
    }
    console.log(`📝 Total Records: ${records.length}\n`);

    if (records.length === 0) {
      console.log('✅ No sync records found for the specified criteria.\n');
      process.exit(0);
    }

    // Display failure summary
    if (!options.entity && !options.showAll) {
      console.log('═══════════════════════════════════════════════════════════');
      console.log('📈 FAILURE SUMMARY BY ENTITY');
      console.log('═══════════════════════════════════════════════════════════\n');

      const summary = await getFailureSummary(options.days);
      
      if (summary.length === 0) {
        console.log('✅ No failures found in the specified period!\n');
      } else {
        summary.forEach(item => {
          console.log(`Entity: ${item.entity_type}`);
          console.log(`  Failures: ${item.failure_count}`);
          console.log(`  Last Failure: ${new Date(item.last_failure).toLocaleString()}`);
          console.log(`  Common Errors:`);
          item.common_errors.slice(0, 3).forEach(err => {
            console.log(`    - ${err.substring(0, 80)}...`);
          });
          console.log();
        });
      }
    }

    // Display detailed records
    console.log('═══════════════════════════════════════════════════════════');
    console.log('📋 DETAILED SYNC RECORDS');
    console.log('═══════════════════════════════════════════════════════════\n');

    // Group by status
    const byStatus = records.reduce((acc, record) => {
      if (!acc[record.status]) acc[record.status] = [];
      acc[record.status].push(record);
      return acc;
    }, {} as Record<string, SyncHistoryRecord[]>);

    Object.entries(byStatus).forEach(([status, statusRecords]) => {
      const statusIcon = status === 'completed' ? '✅' : status === 'failed' ? '❌' : '⏳';
      console.log(`${statusIcon} ${status.toUpperCase()} (${statusRecords.length} records)`);
      console.log('─────────────────────────────────────────────────────────\n');

      statusRecords.forEach(record => {
        const duration = formatDuration(record.started_at, record.completed_at);
        const errorCategory = categorizeError(record.error_message);
        
        console.log(`  ID: ${record.id}`);
        console.log(`  Entity: ${record.entity_type}`);
        console.log(`  Type: ${record.sync_type}`);
        console.log(`  Started: ${new Date(record.started_at).toLocaleString()}`);
        console.log(`  Duration: ${duration}`);
        console.log(`  Records: +${record.records_added} ~${record.records_updated} -${record.records_deleted}`);
        console.log(`  Triggered By: ${record.triggered_by}`);
        
        if (record.error_message) {
          console.log(`  Error Category: ${errorCategory}`);
          console.log(`  Error: ${record.error_message}`);
        }
        
        console.log();
      });
    });

    // Statistics
    console.log('═══════════════════════════════════════════════════════════');
    console.log('📊 STATISTICS');
    console.log('═══════════════════════════════════════════════════════════\n');

    const totalRecordsAdded = records.reduce((sum, r) => sum + r.records_added, 0);
    const totalRecordsUpdated = records.reduce((sum, r) => sum + r.records_updated, 0);
    const totalRecordsDeleted = records.reduce((sum, r) => sum + r.records_deleted, 0);
    const failedCount = records.filter(r => r.status === 'failed').length;
    const completedCount = records.filter(r => r.status === 'completed').length;
    const successRate = records.length > 0 ? ((completedCount / records.length) * 100).toFixed(1) : '0';

    console.log(`Total Syncs: ${records.length}`);
    console.log(`  Completed: ${completedCount}`);
    console.log(`  Failed: ${failedCount}`);
    console.log(`  Success Rate: ${successRate}%`);
    console.log();
    console.log(`Total Records Processed:`);
    console.log(`  Added: ${totalRecordsAdded}`);
    console.log(`  Updated: ${totalRecordsUpdated}`);
    console.log(`  Deleted: ${totalRecordsDeleted}`);
    console.log();

    // Error categories
    if (failedCount > 0) {
      const errorCategories = records
        .filter(r => r.status === 'failed')
        .reduce((acc, r) => {
          const category = categorizeError(r.error_message);
          acc[category] = (acc[category] || 0) + 1;
          return acc;
        }, {} as Record<string, number>);

      console.log('Error Categories:');
      Object.entries(errorCategories)
        .sort(([, a], [, b]) => b - a)
        .forEach(([category, count]) => {
          console.log(`  ${category}: ${count}`);
        });
      console.log();
    }

    console.log('═══════════════════════════════════════════════════════════\n');

  } catch (error) {
    console.error('❌ Analysis failed:', error);
    if (error instanceof Error) {
      console.error('Stack trace:', error.stack);
    }
    process.exit(1);
  } finally {
    await postgresClient.close();
  }
}

// Run analysis
analyzeSyncFailures()
  .then(() => {
    console.log('✅ Analysis complete\n');
    process.exit(0);
  })
  .catch((error) => {
    console.error('❌ Fatal error:', error);
    process.exit(1);
  });
