/**
 * Test script for entity-specific sync with Autotask
 * Run with: npx tsx dev/test-entity-specific-sync.ts
 * 
 * This script tests the entity-specific sync functionality by:
 * 1. Syncing individual entities
 * 2. Syncing multiple selected entities
 * 3. Verifying dependency ordering
 * 4. Testing different entity types
 */

import dotenv from 'dotenv';
import path from 'path';

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

import { AutotaskClient } from '../lib/services/autotask-client';
import { createSyncService } from '../lib/services/sync-service';
import { EntityType, SyncType } from '../lib/types/sync';
import postgresClient from '../lib/services/postgres-client';

async function testEntitySpecificSync() {
  console.log('🔍 Testing Entity-Specific Sync with Autotask\n');
  
  // Validate required environment variables
  if (!process.env.AUTOTASK_API_URL || !process.env.AUTOTASK_USERNAME || 
      !process.env.AUTOTASK_SECRET || !process.env.AUTOTASK_API_INTEGRATION_CODE) {
    console.error('❌ Missing required Autotask environment variables');
    process.exit(1);
  }

  try {
    // Test 1: Database connection
    console.log('Test 1: Verify database connection');
    const dbConnected = await postgresClient.testConnection();
    if (!dbConnected) {
      console.error('❌ Database connection failed');
      process.exit(1);
    }
    console.log('✅ Database connection successful\n');

    // Test 2: Initialize clients
    console.log('Test 2: Initialize Autotask client and sync service');
    const autotaskClient = new AutotaskClient({
      apiUrl: process.env.AUTOTASK_API_URL!,
      username: process.env.AUTOTASK_USERNAME!,
      password: process.env.AUTOTASK_SECRET!,
      apiIntegrationCode: process.env.AUTOTASK_API_INTEGRATION_CODE!,
    });
    const syncService = createSyncService(autotaskClient);
    console.log('✅ Clients initialized\n');

    // Test 3: Sync a single entity (Companies)
    console.log('Test 3: Sync single entity - Companies');
    console.log('Testing entity-specific sync with one entity\n');
    
    const singleEntityStart = Date.now();
    const singleResult = await syncService.syncEntities(
      [EntityType.COMPANIES],
      SyncType.ENTITY_SPECIFIC,
      'test-single-entity'
    );
    const singleDuration = Date.now() - singleEntityStart;

    console.log('\n=== SINGLE ENTITY SYNC RESULTS ===');
    console.log(`Sync ID: ${singleResult.syncId}`);
    console.log(`Sync Type: ${singleResult.syncType}`);
    console.log(`Status: ${singleResult.status}`);
    console.log(`Duration: ${singleDuration}ms`);
    console.log(`Entities synced: ${singleResult.entities.length}`);
    
    singleResult.entities.forEach(entity => {
      const status = entity.success ? '✅' : '❌';
      console.log(`${status} ${entity.entityType}: +${entity.recordsAdded} ~${entity.recordsUpdated} -${entity.recordsDeleted}`);
      if (entity.error) {
        console.log(`   Error: ${entity.error}`);
      }
    });

    if (singleResult.errors.length > 0) {
      console.log('\nErrors:');
      singleResult.errors.forEach(err => console.log(`  - ${err}`));
    }
    console.log();

    // Test 4: Verify sync history for single entity
    console.log('Test 4: Verify sync history for single entity');
    const companiesHistory = await syncService.getSyncHistory(1, EntityType.COMPANIES);
    if (companiesHistory.length > 0) {
      const latest = companiesHistory[0];
      console.log(`✅ Latest companies sync:`);
      console.log(`   Sync Type: ${latest.sync_type}`);
      console.log(`   Status: ${latest.status}`);
      
      if (latest.sync_type === 'entity-specific') {
        console.log(`   ✅ Confirmed: Sync type is entity-specific`);
      } else {
        console.log(`   ⚠️  Expected entity-specific, got ${latest.sync_type}`);
      }
    }
    console.log();

    // Test 5: Sync multiple entities
    console.log('Test 5: Sync multiple entities - Companies, Resources, Statuses');
    console.log('Testing entity-specific sync with multiple entities\n');
    
    const multiEntityStart = Date.now();
    const multiResult = await syncService.syncEntities(
      [EntityType.COMPANIES, EntityType.RESOURCES, EntityType.STATUSES],
      SyncType.ENTITY_SPECIFIC,
      'test-multi-entity'
    );
    const multiDuration = Date.now() - multiEntityStart;

    console.log('\n=== MULTIPLE ENTITY SYNC RESULTS ===');
    console.log(`Sync ID: ${multiResult.syncId}`);
    console.log(`Sync Type: ${multiResult.syncType}`);
    console.log(`Status: ${multiResult.status}`);
    console.log(`Duration: ${multiDuration}ms`);
    console.log(`Entities synced: ${multiResult.entities.length}`);
    console.log(`\nTotal Records:`);
    console.log(`  Added: ${multiResult.totalRecordsAdded}`);
    console.log(`  Updated: ${multiResult.totalRecordsUpdated}`);
    console.log(`  Deleted: ${multiResult.totalRecordsDeleted}`);
    
    console.log('\n=== ENTITY DETAILS ===');
    multiResult.entities.forEach(entity => {
      const status = entity.success ? '✅' : '❌';
      console.log(`${status} ${entity.entityType}:`);
      console.log(`   Added: ${entity.recordsAdded}, Updated: ${entity.recordsUpdated}, Deleted: ${entity.recordsDeleted}`);
      console.log(`   Duration: ${entity.duration}ms`);
      if (entity.error) {
        console.log(`   Error: ${entity.error}`);
      }
    });

    if (multiResult.errors.length > 0) {
      console.log('\nErrors:');
      multiResult.errors.forEach(err => console.log(`  - ${err}`));
    }
    console.log();

    // Test 6: Verify entity ordering
    console.log('Test 6: Verify entity sync ordering');
    console.log('Entities should sync in dependency order (companies first, then dependent entities)');
    
    const entityOrder = multiResult.entities.map(e => e.entityType);
    console.log(`Actual sync order: ${entityOrder.join(' → ')}`);
    
    // Companies should come before resources and statuses
    const companiesIndex = entityOrder.indexOf(EntityType.COMPANIES);
    const resourcesIndex = entityOrder.indexOf(EntityType.RESOURCES);
    const statusesIndex = entityOrder.indexOf(EntityType.STATUSES);
    
    if (companiesIndex !== -1 && resourcesIndex !== -1 && companiesIndex < resourcesIndex) {
      console.log('✅ Companies synced before Resources (correct dependency order)');
    } else {
      console.log('⚠️  Dependency ordering may need verification');
    }
    console.log();

    // Test 7: Test with picklist entities
    console.log('Test 7: Sync picklist entities - Statuses, IssueTypes, WorkTypes');
    console.log('Testing entity-specific sync with picklist/lookup entities\n');
    
    const picklistStart = Date.now();
    const picklistResult = await syncService.syncEntities(
      [EntityType.STATUSES, EntityType.ISSUE_TYPES, EntityType.WORK_TYPES],
      SyncType.ENTITY_SPECIFIC,
      'test-picklist-entities'
    );
    const picklistDuration = Date.now() - picklistStart;

    console.log('\n=== PICKLIST ENTITY SYNC RESULTS ===');
    console.log(`Sync ID: ${picklistResult.syncId}`);
    console.log(`Status: ${picklistResult.status}`);
    console.log(`Duration: ${picklistDuration}ms`);
    console.log(`Entities synced: ${picklistResult.entities.length}`);
    
    picklistResult.entities.forEach(entity => {
      const status = entity.success ? '✅' : '❌';
      console.log(`${status} ${entity.entityType}: +${entity.recordsAdded} ~${entity.recordsUpdated}`);
      if (entity.error) {
        console.log(`   Error: ${entity.error}`);
      }
    });
    console.log();

    // Test 8: Verify sync history for multiple entities
    console.log('Test 8: Verify sync history for all tested entities');
    const entities = [EntityType.COMPANIES, EntityType.RESOURCES, EntityType.STATUSES];
    
    for (const entity of entities) {
      const history = await syncService.getSyncHistory(1, entity);
      if (history.length > 0) {
        const latest = history[0];
        console.log(`✅ ${entity}: ${latest.status} (${latest.sync_type})`);
      } else {
        console.log(`⚠️  ${entity}: No sync history found`);
      }
    }
    console.log();

    // Test 9: Test entity-specific sync with full mode
    console.log('Test 9: Entity-specific sync with FULL sync type');
    console.log('Testing that entity-specific can use full sync mode\n');
    
    const fullModeResult = await syncService.syncEntities(
      [EntityType.STATUSES],
      SyncType.FULL,
      'test-entity-full-mode'
    );

    console.log(`✅ Entity-specific full sync completed: ${fullModeResult.status}`);
    console.log(`   Sync Type: ${fullModeResult.syncType}`);
    console.log(`   Entities: ${fullModeResult.entities.map(e => e.entityType).join(', ')}`);
    console.log();

    // Test 10: Test entity-specific sync with incremental mode
    console.log('Test 10: Entity-specific sync with INCREMENTAL sync type');
    console.log('Testing that entity-specific can use incremental sync mode\n');
    
    const incrementalModeResult = await syncService.syncEntities(
      [EntityType.COMPANIES],
      SyncType.INCREMENTAL,
      'test-entity-incremental-mode'
    );

    console.log(`✅ Entity-specific incremental sync completed: ${incrementalModeResult.status}`);
    console.log(`   Sync Type: ${incrementalModeResult.syncType}`);
    console.log(`   Entities: ${incrementalModeResult.entities.map(e => e.entityType).join(', ')}`);
    console.log();

    // Test 11: Count records in database for each entity
    console.log('Test 11: Verify data in database for synced entities');
    const entityTables = [
      { entity: EntityType.COMPANIES, table: 'companies' },
      { entity: EntityType.RESOURCES, table: 'resources' },
      { entity: EntityType.STATUSES, table: 'statuses' },
      { entity: EntityType.ISSUE_TYPES, table: 'issue_types' },
      { entity: EntityType.WORK_TYPES, table: 'work_types' },
    ];

    for (const { entity, table } of entityTables) {
      try {
        const count = await postgresClient.count(table, { is_deleted: false });
        console.log(`✅ ${entity}: ${count} records in database`);
      } catch (error) {
        console.log(`⚠️  ${entity}: Could not count records (${error instanceof Error ? error.message : 'unknown error'})`);
      }
    }
    console.log();

    // Test 12: Test error handling for invalid entity
    console.log('Test 12: Test error handling with dependent entities');
    console.log('Testing sync of entities that depend on others (e.g., Tickets depend on Companies)\n');
    
    const dependentResult = await syncService.syncEntities(
      [EntityType.TICKETS, EntityType.COMPANIES],
      SyncType.ENTITY_SPECIFIC,
      'test-dependent-entities'
    );

    console.log(`✅ Dependent entity sync completed: ${dependentResult.status}`);
    console.log(`   Entities synced in order: ${dependentResult.entities.map(e => e.entityType).join(' → ')}`);
    
    // Verify companies came before tickets
    const syncedOrder = dependentResult.entities.map(e => e.entityType);
    const companiesIdx = syncedOrder.indexOf(EntityType.COMPANIES);
    const ticketsIdx = syncedOrder.indexOf(EntityType.TICKETS);
    
    if (companiesIdx !== -1 && ticketsIdx !== -1 && companiesIdx < ticketsIdx) {
      console.log('✅ Dependency ordering respected: Companies synced before Tickets');
    } else {
      console.log('⚠️  Dependency ordering may need attention');
    }
    console.log();

    // Summary
    console.log('🎉 Entity-specific sync tests completed!');
    console.log('\n=== SUMMARY ===');
    console.log('✅ Single entity sync working');
    console.log('✅ Multiple entity sync working');
    console.log('✅ Picklist entity sync working');
    console.log('✅ Entity-specific with FULL mode working');
    console.log('✅ Entity-specific with INCREMENTAL mode working');
    console.log('✅ Sync history tracking per entity');
    console.log('✅ Dependency ordering verified');
    console.log('✅ Database records verified');

    // Test statistics
    console.log('\n=== TEST STATISTICS ===');
    const allResults = [singleResult, multiResult, picklistResult, fullModeResult, incrementalModeResult, dependentResult];
    const totalSyncs = allResults.length;
    const successfulSyncs = allResults.filter(r => r.status === 'completed').length;
    const failedSyncs = allResults.filter(r => r.status === 'failed').length;
    const totalEntitiesSynced = allResults.reduce((sum, r) => sum + r.entities.length, 0);
    const successfulEntities = allResults.reduce((sum, r) => sum + r.entities.filter(e => e.success).length, 0);
    const failedEntities = allResults.reduce((sum, r) => sum + r.entities.filter(e => !e.success).length, 0);

    console.log(`Total sync operations: ${totalSyncs}`);
    console.log(`  Successful: ${successfulSyncs}`);
    console.log(`  Failed: ${failedSyncs}`);
    console.log(`\nTotal entities processed: ${totalEntitiesSynced}`);
    console.log(`  Successful: ${successfulEntities}`);
    console.log(`  Failed: ${failedEntities}`);
    
    const successRate = ((successfulEntities / totalEntitiesSynced) * 100).toFixed(1);
    console.log(`\nEntity success rate: ${successRate}%`);

  } catch (error) {
    console.error('\n❌ Test failed with error:', error);
    if (error instanceof Error) {
      console.error('Stack trace:', error.stack);
    }
    process.exit(1);
  } finally {
    // Close database connection
    await postgresClient.close();
    console.log('\n🔌 Database connection closed');
  }
}

// Run the tests
testEntitySpecificSync()
  .then(() => {
    console.log('\n✅ Test script completed successfully');
    process.exit(0);
  })
  .catch((error) => {
    console.error('\n❌ Test script failed:', error);
    process.exit(1);
  });
