const fs = require('fs');
const path = require('path');
const { PrismaClient } = require('@prisma/client');
const { PrismaPg } = require('@prisma/adapter-pg');
const { Pool } = require('pg');
require('dotenv').config();

// Base configurations - Target the dev server directly via localhost port
const BASE_URL = "http://127.0.0.1:3001";

let prisma;
let pool;
const deployedWorkflowIds = [];
let n8nUrl;
let n8nApiKey;

// Helper to run query with admin credentials
function getPrisma() {
  if (!prisma) {
    const dbUrl = new URL(process.env.DATABASE_URL_DEV || process.env.DATABASE_URL);
    pool = new Pool({
      host: dbUrl.hostname,
      port: dbUrl.port ? parseInt(dbUrl.port) : 5432,
      user: decodeURIComponent(dbUrl.username),
      password: decodeURIComponent(dbUrl.password),
      database: dbUrl.pathname.substring(1).split('?')[0],
      ssl: false
    });
    const adapter = new PrismaPg(pool);
    prisma = new PrismaClient({ adapter });
  }
  return prisma;
}

async function runAsAdmin(queryFn) {
  const db = getPrisma();
  return db.$transaction(async (tx) => {
    await tx.$executeRawUnsafe(`SET LOCAL app.current_user_role = 'admin';`);
    return queryFn(tx);
  });
}

async function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// Custom simple assertion
let passed = 0;
let failed = 0;
function assert(condition, message) {
  if (condition) {
    console.log(`  ✓ PASS: ${message}`);
    passed++;
  } else {
    console.error(`  ✗ FAIL: ${message}`);
    failed++;
  }
}

async function cleanupDb() {
  console.log("Cleaning up integration test records in test database...");
  try {
    await runAsAdmin(async (tx) => {
      // Clean sales results
      await tx.salesResult.deleteMany({
        where: {
          OR: [
            { idempotencyKey: { startsWith: 'key-integration' } },
            { period: '2026-07' }
          ]
        }
      });
      // Clean import jobs
      if (tx.salesImportJob) {
        await tx.salesImportJob.deleteMany({
          where: {
            idempotencyKey: { startsWith: 'key-integration' }
          }
        });
      }
      // Clean settlements
      await tx.settlement.deleteMany({
        where: {
          period: '2026-07'
        }
      });
      // Clean goals
      await tx.goal.deleteMany({
        where: {
          period: '2026-07'
        }
      });
      // Clean test plans
      await tx.calculationRule.deleteMany({
        where: { plan: { code: 'PLAN-INT-P5' } }
      });
      await tx.compensationPlan.deleteMany({
        where: { code: 'PLAN-INT-P5' }
      });
      // Clean audit logs
      await tx.auditLog.deleteMany({
        where: {
          action: 'CREATE',
          targetTable: 'sales_results'
        }
      });
    });
  } catch (err) {
    console.error("Error during DB cleanup:", err);
  }
}

async function runTests() {
  console.log("=== STARTING REAL N8N E2E INTEGRATION TEST SUITE ===");

  // 1. Clean DB
  await cleanupDb();

  // 2. Fetch n8n API configuration
  const mcpConfigPath = path.join(__dirname, '../.agents/mcp_config.json');
  if (!fs.existsSync(mcpConfigPath)) {
    console.error("Error: .agents/mcp_config.json not found.");
    process.exit(1);
  }
  
  const mcpConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'));
  const n8nEnv = mcpConfig.mcpServers.n8n.env;
  n8nUrl = n8nEnv.N8N_API_URL || "https://n8n.gaboggamer.online";
  n8nApiKey = n8nEnv.N8N_API_KEY;

  if (!n8nApiKey) {
    console.error("Error: N8N_API_KEY is missing in mcp_config.json.");
    process.exit(1);
  }

  // 3. Spawn n8n bootstrap to ensure permanent workflows are deployed and active
  console.log("Running n8n bootstrap/kickstarter to deploy permanent workflows...");
  const { execSync } = require('child_process');
  try {
    execSync('node scripts/n8n-bootstrap.js', { stdio: 'inherit' });
  } catch (err) {
    console.error("Failed to run n8n bootstrap:", err.message);
  }

  // 4. Fetch existing workflows to retrieve the project ID dynamically and clean up old test workflows
  console.log("Fetching workflows from n8n to clean up old test workflows and retrieve project ID...");
  let projectId;
  try {
    const listRes = await fetch(`${n8nUrl}/api/v1/workflows`, {
      method: 'GET',
      headers: {
        'X-N8N-API-KEY': n8nApiKey
      }
    });
    if (listRes.ok) {
      const listData = await listRes.json();
      const firstWf = listData.data.find(w => w.shared && w.shared.length > 0);
      if (firstWf) {
        projectId = firstWf.shared[0].projectId;
        console.log(`Resolved project ID dynamically: ${projectId}`);
      }

      // Cleanup any leftover old test workflows
      for (const wf of listData.data) {
        if (wf.name.startsWith('Semillero E2E Integration:')) {
          console.log(`Deleting leftover workflow: ${wf.name} (${wf.id})`);
          await fetch(`${n8nUrl}/api/v1/workflows/${wf.id}`, {
            method: 'DELETE',
            headers: { 'X-N8N-API-KEY': n8nApiKey }
          });
        }
      }
    }
  } catch (err) {
    console.warn("Warning: Could not fetch project ID or clean up workflows:", err.message);
  }

  // 5. Verify the external dev server is running
  console.log(`Verifying target dev server at ${BASE_URL}...`);
  try {
    const res = await fetch(`${BASE_URL}/api/auth/me`);
    if (!res.ok) {
      console.warn(`Warning: Target server returned status ${res.status}`);
    }
  } catch (e) {
    console.error(`Error: Dev server is unreachable at ${BASE_URL}. Error:`, e.message);
    await cleanup();
    process.exit(1);
  }


  // ==========================================
  // TEST CASE 0: WORKFLOW CREATION AND DELETION API
  // ==========================================
  console.log("\n[Test 0] Verifying workflow creation and deletion via n8n API...");
  let tempWorkflowId;
  try {
    const createRes = await fetch(`${n8nUrl}/api/v1/workflows`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'X-N8N-API-KEY': n8nApiKey },
      body: JSON.stringify({
        name: `Semillero E2E Integration: API Test Temp - ${Date.now()}`,
        nodes: [],
        connections: {},
        settings: {},
        projectId
      })
    });
    if (!createRes.ok) {
      console.error(`Workflow creation failed. Status: ${createRes.status}`, await createRes.text());
    }
    assert(createRes.ok, "API: Successfully created a temporary workflow in n8n");
    if (createRes.ok) {
      const createData = await createRes.json();
      tempWorkflowId = createData.id;
      const deleteRes = await fetch(`${n8nUrl}/api/v1/workflows/${tempWorkflowId}`, {
        method: 'DELETE',
        headers: { 'X-N8N-API-KEY': n8nApiKey }
      });
      assert(deleteRes.ok, "API: Successfully deleted the temporary workflow in n8n");
    }
  } catch (err) {
    console.error("API test failed:", err.message);
    failed++;
  }

  // ==========================================
  // TEST CASE 1: SALES IMPORT WORKFLOW
  // ==========================================
  console.log("\n[Test 1] Triggering Sales Import Workflow...");
  const importIdempotencyKey = `key-integration-import-${Date.now()}`;
  const uploadRes = await fetch(`${n8nUrl}/webhook/calculate-commissions`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-n8n-signature': process.env.N8N_WEBHOOK_SECRET_DEV || 'qUHuPqPjA65psdtwQU7zgp/DVkvd1xXk2WP/vzbnEdc=',
      'x-semillero-env': 'dev'
    },
    body: JSON.stringify({
      idempotencyKey: importIdempotencyKey,
      uploaderId: 1,
      sales: [
        {
          username: 'colaborador_mde',
          hotelCode: 'EST-MDE',
          period: '2026-06',
          amount: 2000000,
          salesCount: 5,
          transactionId: `TX-INT-COMM-${Date.now()}`
        }
      ]
    })
  });

  assert(uploadRes.status === 200 || uploadRes.status === 202, `Import webhook response code: ${uploadRes.status}`);
  const uploadData = await uploadRes.json();
  assert(uploadData.success && uploadData.code === 'IMPORT_ACCEPTED', "Import accepted by n8n");

  let importCallbackCompleted = false;
  for (let i = 0; i < 20; i++) {
    await sleep(2000);
    const dbSales = await runAsAdmin(tx => tx.salesResult.findMany({
      where: { idempotencyKey: { startsWith: importIdempotencyKey } }
    }));
    if (dbSales.length > 0) {
      assert(dbSales.length === 1, "Sales result saved to dev database by n8n callback");
      assert(parseFloat(dbSales[0].amount) === 2000000.00, "Imported amount verified");
      assert(dbSales[0].isAnomaly === true, "isAnomaly flag correctly set to true");
      assert(dbSales[0].flaggedReason && typeof dbSales[0].flaggedReason === 'object', "flaggedReason is stored as a JSON object");
      assert(dbSales[0].flaggedReason.en.includes("exceeds normal threshold limits"), "flaggedReason English matches expected text");
      assert(dbSales[0].flaggedReason.es.includes("excede") || dbSales[0].flaggedReason.es.includes("umbral"), "flaggedReason Spanish contains translation");
      importCallbackCompleted = true;
      break;
    }
  }
  assert(importCallbackCompleted, "Sales import integration completed successfully");

  // ==========================================
  // TEST CASE 2: SETTLEMENT CALCULATION WORKFLOW
  // ==========================================
  console.log("\n[Test 2] Triggering Settlement Calculation Workflow...");

  // Seed DB records for the calculation E2E test
  console.log("Seeding test database with plan, rules, goal, and sales results for calculation E2E test...");
  const adminUser = (await runAsAdmin(tx => tx.user.findMany())).find(u => u.username === 'admin');
  const colaboradorMde = (await runAsAdmin(tx => tx.user.findMany())).find(u => u.username === 'colaborador_mde');

  const testPlan = await runAsAdmin(async (tx) => {
    // Delete existing PLAN-INT-P5 if any
    await tx.calculationRule.deleteMany({ where: { plan: { code: 'PLAN-INT-P5' } } });
    await tx.compensationPlan.deleteMany({ where: { code: 'PLAN-INT-P5' } });

    const plan = await tx.compensationPlan.create({
      data: {
        name: 'Integration Test Plan Phase 5',
        code: 'PLAN-INT-P5',
        validityStart: new Date('2026-01-01'),
        type: 'SCALE',
        status: 'ACTIVE',
        version: 1,
        createdBy: adminUser.id
      }
    });

    await tx.calculationRule.create({
      data: {
        planId: plan.id,
        type: 'TIER',
        minAchievement: 0.0,
        maxAchievement: 2.0,
        rate: 0.02,
        payoutAmount: 0.0
      }
    });

    return plan;
  });

  // Seed Goal and SalesResult for period 2026-07
  await runAsAdmin(async (tx) => {
    await tx.goal.deleteMany({ where: { period: '2026-07', targetId: colaboradorMde.id } });
    await tx.goal.create({
      data: {
        targetType: 'INDIVIDUAL',
        targetId: colaboradorMde.id,
        period: '2026-07',
        amount: 500000.00
      }
    });

    await tx.salesResult.deleteMany({ where: { period: '2026-07', userId: colaboradorMde.id } });
    await tx.salesResult.create({
      data: {
        source: 'API',
        hotelId: colaboradorMde.hotelId,
        userId: colaboradorMde.id,
        period: '2026-07',
        amount: 600000.00,
        salesCount: 2,
        idempotencyKey: 'key-integration-sales-p5',
        uploadedBy: adminUser.id,
        status: 'PENDING'
      }
    });
  });

  // Trigger calculation webhook (commit mode)
  console.log(`Triggering settlement calculation webhook directly at ${n8nUrl}/webhook/calculate-settlements...`);
  const calcRes = await fetch(`${n8nUrl}/webhook/calculate-settlements`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-n8n-signature': process.env.N8N_WEBHOOK_SECRET_DEV || 'qUHuPqPjA65psdtwQU7zgp/DVkvd1xXk2WP/vzbnEdc=',
      'x-semillero-env': 'dev'
    },
    body: JSON.stringify({
      period: '2026-07',
      simulateOnly: false,
      uploaderId: adminUser.id
    })
  });

  assert(calcRes.status === 200 || calcRes.status === 201, `Calculation webhook response code: ${calcRes.status}`);
  const calcData = await calcRes.json();
  assert(calcData.success && calcData.code === 'SETTLEMENTS_CALCULATED', "Calculation execution successful");

  // Verify settlement created in database
  const finalSettlement = await runAsAdmin(tx => tx.settlement.findFirst({
    where: {
      userId: colaboradorMde.id,
      period: '2026-07',
      planId: testPlan.id
    }
  }));

  assert(finalSettlement !== null, "Settlement record created in database for colaborador_mde in 2026-07");
  if (finalSettlement) {
    assert(finalSettlement.status === 'PENDING', "Settlement status is set to PENDING");
    assert(parseFloat(finalSettlement.calculatedCommission) === 12000.00, "Calculated commission is correctly 12,000.00 (600,000 * 2%)");
    assert(parseFloat(finalSettlement.totalPayout) === 12000.00, "Total payout is correctly 12,000.00");
    assert(finalSettlement.aiAudited === true, "aiAudited flag correctly set to true");
    assert(finalSettlement.aiAuditNotes && typeof finalSettlement.aiAuditNotes === 'object', "aiAuditNotes is stored as a JSON object");
    assert(finalSettlement.aiAuditNotes.en.includes("High commission payout"), "aiAuditNotes English contains warning text");
    assert(finalSettlement.aiAuditNotes.es.includes("comisión alto") || finalSettlement.aiAuditNotes.es.includes("umbral"), "aiAuditNotes Spanish contains translation");
  }

  await cleanup();

  console.log(`\n=== REAL N8N INTEGRATION TEST RESULTS: ${passed} PASSED, ${failed} FAILED ===`);
  if (failed > 0) {
    process.exit(1);
  } else {
    process.exit(0);
  }
}

async function cleanup() {
  console.log("\nCleaning up integration test processes...");
  
  // 1. Delete all deployed workflows from n8n starting with 'Semillero E2E Integration:'
  try {
    const listRes = await fetch(`${n8nUrl}/api/v1/workflows`, {
      method: 'GET',
      headers: {
        'X-N8N-API-KEY': n8nApiKey
      }
    });
    if (listRes.ok) {
      const listData = await listRes.json();
      for (const wf of listData.data) {
        if (wf.name.startsWith('Semillero E2E Integration:')) {
          console.log(`Cleaning up workflow: ${wf.name} (${wf.id})`);
          await fetch(`${n8nUrl}/api/v1/workflows/${wf.id}`, {
            method: 'DELETE',
            headers: { 'X-N8N-API-KEY': n8nApiKey }
          });
        }
      }
    }
  } catch (err) {
    console.warn("Warning during cleanup: Could not clean up workflows:", err.message);
  }

  // 2. Clean DB records
  await cleanupDb();

  // 3. Disconnect Prisma
  try {
    if (prisma) {
      await prisma.$disconnect();
    }
    if (pool) {
      await pool.end();
    }
  } catch (e) {}
}

process.on('SIGINT', async () => {
  await cleanup();
  process.exit(1);
});

runTests().catch(async err => {
  console.error("Fatal E2E integration test runner error:", err);
  failed++;
  await cleanup();
  process.exit(1);
});
