import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from '@jest/globals';
import request from 'supertest';
import { app } from '../app';

describe('Comprehensive System Tests', () => {
  let authToken: string;
  let testTenantId: string;
  let testShopId: string;
  let testProductId: string;
  let testOrderId: string;

  beforeAll(async () => {
    console.log('🚀 Starting Comprehensive System Tests...');
    
    const loginResponse = await request(app)
      .post('/api/auth/login')
      .send({
        email: 'test-admin@crawlful.com',
        password: 'test-password-123'
      });

    authToken = loginResponse.body.token;
    testTenantId = loginResponse.body.user.tenantId;
    testShopId = loginResponse.body.user.shopId;
  });

  afterAll(() => {
    console.log('✅ Comprehensive System Tests Completed');
  });

  describe('Authentication & Authorization', () => {
    it('should login with valid credentials', async () => {
      const response = await request(app)
        .post('/api/auth/login')
        .send({
          email: 'test-admin@crawlful.com',
          password: 'test-password-123'
        });

      expect(response.status).toBe(200);
      expect(response.body.token).toBeDefined();
      expect(response.body.user).toBeDefined();
    });

    it('should reject invalid credentials', async () => {
      const response = await request(app)
        .post('/api/auth/login')
        .send({
          email: 'test-admin@crawlful.com',
          password: 'wrong-password'
        });

      expect(response.status).toBe(401);
      expect(response.body.error).toBeDefined();
    });

    it('should require authentication for protected routes', async () => {
      const response = await request(app)
        .get('/api/products')
        .set('Authorization', 'Bearer invalid-token');

      expect(response.status).toBe(401);
    });

    it('should validate RBAC permissions', async () => {
      const response = await request(app)
        .post('/api/users')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: 'Test User',
          email: 'test-user@crawlful.com',
          role: 'ADMIN'
        });

      expect(response.status).toBe(403);
      expect(response.body.error).toContain('permission');
    });
  });

  describe('Product Management', () => {
    it('should create a new product', async () => {
      const response = await request(app)
        .post('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: 'Test Product',
          description: 'Test product description',
          price: 99.99,
          currency: 'USD',
          platform: 'AMAZON',
          productId: 'TEST-001'
        });

      expect(response.status).toBe(201);
      expect(response.body.product).toBeDefined();
      expect(response.body.product.name).toBe('Test Product');
      testProductId = response.body.product.id;
    });

    it('should retrieve product list', async () => {
      const response = await request(app)
        .get('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .query({
          tenantId: testTenantId,
          shopId: testShopId
        });

      expect(response.status).toBe(200);
      expect(Array.isArray(response.body.products)).toBe(true);
      expect(response.body.products.length).toBeGreaterThan(0);
    });

    it('should update product information', async () => {
      const response = await request(app)
        .put(`/api/products/${testProductId}`)
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: 'Updated Test Product',
          price: 149.99
        });

      expect(response.status).toBe(200);
      expect(response.body.product.name).toBe('Updated Test Product');
      expect(response.body.product.price).toBe(149.99);
    });

    it('should delete product', async () => {
      const response = await request(app)
        .delete(`/api/products/${testProductId}`)
        .set('Authorization', `Bearer ${authToken}`);

      expect(response.status).toBe(200);
      expect(response.body.message).toContain('deleted');
    });
  });

  describe('Order Management', () => {
    it('should create a new order', async () => {
      const response = await request(app)
        .post('/api/orders')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          customerName: 'Test Customer',
          customerEmail: 'test-customer@example.com',
          totalAmount: 199.99,
          currency: 'USD',
          platform: 'AMAZON',
          platformOrderId: 'AMZ-TEST-001'
        });

      expect(response.status).toBe(201);
      expect(response.body.order).toBeDefined();
      expect(response.body.order.customerName).toBe('Test Customer');
      testOrderId = response.body.order.id;
    });

    it('should retrieve order list', async () => {
      const response = await request(app)
        .get('/api/orders')
        .set('Authorization', `Bearer ${authToken}`)
        .query({
          tenantId: testTenantId,
          shopId: testShopId
        });

      expect(response.status).toBe(200);
      expect(Array.isArray(response.body.orders)).toBe(true);
    });

    it('should update order status', async () => {
      const response = await request(app)
        .put(`/api/orders/${testOrderId}/status`)
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          status: 'CONFIRMED'
        });

      expect(response.status).toBe(200);
      expect(response.body.order.status).toBe('CONFIRMED');
    });
  });

  describe('Pricing & Profit Calculation', () => {
    it('should calculate product pricing', async () => {
      const response = await request(app)
        .post('/api/pricing/calculate')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          productId: testProductId,
          costPrice: 50.00,
          platform: 'AMAZON',
          marketplace: 'US'
        });

      expect(response.status).toBe(200);
      expect(response.body.pricing).toBeDefined();
      expect(response.body.pricing.suggestedPrice).toBeGreaterThan(50.00);
      expect(response.body.pricing.profitMargin).toBeDefined();
    });

    it('should validate profit margin thresholds', async () => {
      const response = await request(app)
        .post('/api/pricing/calculate')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          productId: testProductId,
          costPrice: 80.00,
          platform: 'AMAZON',
          marketplace: 'US',
          businessType: 'TOB'
        });

      expect(response.status).toBe(200);
      
      if (response.body.pricing.profitMargin < 15) {
        expect(response.body.pricing.warning).toContain('below minimum');
      }
    });
  });

  describe('Billing & Settlement', () => {
    it('should generate invoice', async () => {
      const response = await request(app)
        .post('/api/billing/invoices')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          orderId: testOrderId,
          items: [
            {
              description: 'Product 1',
              quantity: 1,
              unitPrice: 99.99
            }
          ],
          totalAmount: 99.99
        });

      expect(response.status).toBe(201);
      expect(response.body.invoice).toBeDefined();
      expect(response.body.invoice.invoiceNumber).toBeDefined();
    });

    it('should process settlement', async () => {
      const response = await request(app)
        .post('/api/billing/settlements')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          tenantId: testTenantId,
          settlementDate: new Date().toISOString().split('T')[0],
          currency: 'USD',
          totalAmount: 1000.00
        });

      expect(response.status).toBe(201);
      expect(response.body.settlement).toBeDefined();
    });
  });

  describe('Analytics & Reporting', () => {
    it('should generate sales report', async () => {
      const response = await request(app)
        .post('/api/analytics/reports/sales')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          startDate: '2026-01-01',
          endDate: '2026-03-31',
          tenantId: testTenantId,
          shopId: testShopId
        });

      expect(response.status).toBe(200);
      expect(response.body.report).toBeDefined();
      expect(response.body.report.totalSales).toBeDefined();
      expect(response.body.report.orderCount).toBeDefined();
    });

    it('should generate profit report', async () => {
      const response = await request(app)
        .post('/api/analytics/reports/profit')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          startDate: '2026-01-01',
          endDate: '2026-03-31',
          tenantId: testTenantId
        });

      expect(response.status).toBe(200);
      expect(response.body.report).toBeDefined();
      expect(response.body.report.totalRevenue).toBeDefined();
      expect(response.body.report.totalCost).toBeDefined();
      expect(response.body.report.netProfit).toBeDefined();
    });
  });

  describe('Compliance & Certificates', () => {
    it('should upload certificate', async () => {
      const response = await request(app)
        .post('/api/compliance/certificates')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: 'Test Certificate',
          type: 'BUSINESS_LICENSE',
          issueDate: '2026-01-01',
          expiryDate: '2027-01-01',
          issuer: 'Test Authority',
          certificateNumber: 'TEST-123456'
        });

      expect(response.status).toBe(201);
      expect(response.body.certificate).toBeDefined();
    });

    it('should perform compliance check', async () => {
      const response = await request(app)
        .post('/api/compliance/checks')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          productId: testProductId,
          checkType: 'PRODUCT_COMPLIANCE'
        });

      expect(response.status).toBe(200);
      expect(response.body.check).toBeDefined();
      expect(response.body.check.status).toBeDefined();
    });
  });

  describe('AI Services', () => {
    it('should get AI pricing recommendations', async () => {
      const response = await request(app)
        .post('/api/ai/pricing/recommend')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          productId: testProductId,
          historicalData: {
            salesVolume: 100,
            averagePrice: 89.99,
            competitorPrices: [85.00, 95.00, 99.99]
          }
        });

      expect(response.status).toBe(200);
      expect(response.body.recommendation).toBeDefined();
      expect(response.body.recommendation.suggestedPrice).toBeDefined();
      expect(response.body.recommendation.confidence).toBeDefined();
    });

    it('should get AI insights', async () => {
      const response = await request(app)
        .get('/api/ai/insights')
        .set('Authorization', `Bearer ${authToken}`)
        .query({
          tenantId: testTenantId,
          type: 'sales_trend'
        });

      expect(response.status).toBe(200);
      expect(response.body.insights).toBeDefined();
      expect(Array.isArray(response.body.insights)).toBe(true);
    });
  });

  describe('Multi-Tenant Isolation', () => {
    it('should respect tenant isolation', async () => {
      const response = await request(app)
        .get('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .query({
          tenantId: 'different-tenant-id'
        });

      expect(response.status).toBe(200);
      expect(response.body.products).toHaveLength(0);
    });

    it('should prevent cross-tenant access', async () => {
      const response = await request(app)
        .get(`/api/orders/${testOrderId}`)
        .set('Authorization', `Bearer ${authToken}`)
        .query({
          tenantId: 'different-tenant-id'
        });

      expect(response.status).toBe(403);
      expect(response.body.error).toContain('tenant');
    });
  });

  describe('Performance & Load Testing', () => {
    it('should handle concurrent requests', async () => {
      const concurrentRequests = Array(10).fill(null).map((_, i) => 
        request(app)
          .get('/api/products')
          .set('Authorization', `Bearer ${authToken}`)
          .query({ tenantId: testTenantId, shopId: testShopId })
      );

      const responses = await Promise.all(concurrentRequests);
      
      responses.forEach(response => {
        expect(response.status).toBe(200);
      });
    });

    it('should respond within acceptable time limits', async () => {
      const startTime = Date.now();
      
      const response = await request(app)
        .get('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .query({ tenantId: testTenantId, shopId: testShopId });
      
      const responseTime = Date.now() - startTime;
      
      expect(response.status).toBe(200);
      expect(responseTime).toBeLessThan(1000); // Less than 1 second
    });
  });

  describe('Security & Data Protection', () => {
    it('should sanitize input to prevent SQL injection', async () => {
      const response = await request(app)
        .post('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: "'; DROP TABLE cf_product; --",
          description: 'SQL injection attempt',
          price: 99.99
        });

      expect(response.status).toBe(400);
      expect(response.body.error).toContain('invalid');
    });

    it('should protect against XSS attacks', async () => {
      const response = await request(app)
        .post('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: '<script>alert("XSS")</script>',
          description: 'XSS attempt',
          price: 99.99
        });

      expect(response.status).toBe(400);
      expect(response.body.error).toContain('invalid');
    });

    it('should implement rate limiting', async () => {
      const requests = Array(20).fill(null).map(() => 
        request(app)
          .get('/api/products')
          .set('Authorization', `Bearer ${authToken}`)
      );

      const responses = await Promise.all(requests);
      const rateLimitedResponses = responses.filter(r => r.status === 429);
      
      expect(rateLimitedResponses.length).toBeGreaterThan(0);
    });
  });

  describe('Error Handling & Recovery', () => {
    it('should handle database connection errors gracefully', async () => {
      const response = await request(app)
        .get('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .query({ forceDbError: true });

      expect(response.status).toBe(500);
      expect(response.body.error).toBeDefined();
      expect(response.body.error).not.toContain('password');
    });

    it('should implement proper error codes', async () => {
      const notFoundResponse = await request(app)
        .get('/api/products/non-existent-id')
        .set('Authorization', `Bearer ${authToken}`);

      expect(notFoundResponse.status).toBe(404);

      const unauthorizedResponse = await request(app)
        .post('/api/auth/login')
        .send({ email: 'test@test.com', password: 'wrong' });

      expect(unauthorizedResponse.status).toBe(401);
    });

    it('should provide meaningful error messages', async () => {
      const response = await request(app)
        .post('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: '', // Invalid: empty name
          price: -99.99 // Invalid: negative price
        });

      expect(response.status).toBe(400);
      expect(response.body.error).toBeDefined();
      expect(response.body.error).toContain('name');
      expect(response.body.error).toContain('price');
    });
  });

  describe('Integration Tests', () => {
    it('should complete full order lifecycle', async () => {
      // Create product
      const productResponse = await request(app)
        .post('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          name: 'Integration Test Product',
          price: 199.99,
          currency: 'USD',
          platform: 'AMAZON'
        });

      expect(productResponse.status).toBe(201);
      const productId = productResponse.body.product.id;

      // Create order
      const orderResponse = await request(app)
        .post('/api/orders')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          customerName: 'Integration Customer',
          totalAmount: 199.99,
          platform: 'AMAZON',
          items: [{ productId, quantity: 1 }]
        });

      expect(orderResponse.status).toBe(201);
      const orderId = orderResponse.body.order.id;

      // Update order status
      const statusResponse = await request(app)
        .put(`/api/orders/${orderId}/status`)
        .set('Authorization', `Bearer ${authToken}`)
        .send({ status: 'CONFIRMED' });

      expect(statusResponse.status).toBe(200);

      // Generate invoice
      const invoiceResponse = await request(app)
        .post('/api/billing/invoices')
        .set('Authorization', `Bearer ${authToken}`)
        .send({
          orderId,
          totalAmount: 199.99
        });

      expect(invoiceResponse.status).toBe(201);

      // Verify all components are connected
      expect(invoiceResponse.body.invoice.orderId).toBe(orderId);
      expect(orderResponse.body.order.items[0].productId).toBe(productId);
    });

    it('should maintain data consistency across services', async () => {
      const productData = {
        name: 'Consistency Test Product',
        price: 149.99,
        currency: 'USD',
        platform: 'AMAZON'
      };

      const productResponse = await request(app)
        .post('/api/products')
        .set('Authorization', `Bearer ${authToken}`)
        .send(productData);

      expect(productResponse.status).toBe(201);
      const productId = productResponse.body.product.id;

      const retrievedProduct = await request(app)
        .get(`/api/products/${productId}`)
        .set('Authorization', `Bearer ${authToken}`);

      expect(retrievedProduct.body.product.name).toBe(productData.name);
      expect(retrievedProduct.body.product.price).toBe(productData.price);
    });
  });
});