/**
 * Carrier Portal E2E Tests
 *
 * Tests the complete carrier portal workflow including:
 * - Account creation
 * - Authentication
 * - Dashboard access
 * - Booking management
 */

import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import request from 'supertest';
import { AppModule } from '../src/app.module';

describe('Carrier Portal (e2e)', () => {
  let app: INestApplication;
  let carrierAccessToken: string;
  let _carrierId: string;
  let bookingId: string;

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
    await app.init();
  });

  afterAll(async () => {
    await app.close();
  });

  describe('Authentication', () => {
    describe('POST /api/v1/carrier-auth/login', () => {
      it('should login with valid credentials', () => {
        return request(app.getHttpServer())
          .post('/api/v1/carrier-auth/login')
          .send({
            email: 'test.carrier@example.com',
            password: 'ValidPassword123!',
          })
          .expect(200)
          .expect((res: any) => {
            expect(res.body).toHaveProperty('accessToken');
            expect(res.body).toHaveProperty('refreshToken');
            expect(res.body).toHaveProperty('carrier');
            expect(res.body.carrier).toHaveProperty('id');
            expect(res.body.carrier).toHaveProperty('companyName');
            expect(res.body.carrier).toHaveProperty('email');

            // Save tokens for subsequent tests
            carrierAccessToken = res.body.accessToken;
            _carrierId = res.body.carrier.id;
          });
      });

      it('should return 401 for invalid credentials', () => {
        return request(app.getHttpServer())
          .post('/api/v1/carrier-auth/login')
          .send({
            email: 'test.carrier@example.com',
            password: 'WrongPassword',
          })
          .expect(401);
      });

      it('should return 400 for invalid email format', () => {
        return request(app.getHttpServer())
          .post('/api/v1/carrier-auth/login')
          .send({
            email: 'invalid-email',
            password: 'Password123!',
          })
          .expect(400);
      });

      it('should return 400 for missing required fields', () => {
        return request(app.getHttpServer())
          .post('/api/v1/carrier-auth/login')
          .send({
            email: 'test@example.com',
          })
          .expect(400);
      });
    });

    describe('POST /api/v1/carrier-auth/verify-auto-login', () => {
      it('should verify valid auto-login token', async () => {
        // This would require generating a valid auto-login token first
        // For now, we'll test with an invalid token to verify error handling
        return request(app.getHttpServer())
          .post('/api/v1/carrier-auth/verify-auto-login')
          .send({
            token: 'invalid-token',
          })
          .expect(401);
      });
    });

    describe('GET /api/v1/carrier-auth/me', () => {
      it('should get carrier profile with valid token', () => {
        return request(app.getHttpServer())
          .get('/api/v1/carrier-auth/me')
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .expect(200)
          .expect((res: any) => {
            expect(res.body).toHaveProperty('id');
            expect(res.body).toHaveProperty('companyName');
            expect(res.body).toHaveProperty('email');
            expect(res.body).toHaveProperty('isVerified');
            expect(res.body).toHaveProperty('totalBookingsAccepted');
          });
      });

      it('should return 401 without auth token', () => {
        return request(app.getHttpServer()).get('/api/v1/carrier-auth/me').expect(401);
      });
    });

    describe('PATCH /api/v1/carrier-auth/change-password', () => {
      it('should change password with valid credentials', () => {
        return request(app.getHttpServer())
          .patch('/api/v1/carrier-auth/change-password')
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .send({
            oldPassword: 'ValidPassword123!',
            newPassword: 'NewValidPassword123!',
          })
          .expect(200);
      });

      it('should return 401 for invalid old password', () => {
        return request(app.getHttpServer())
          .patch('/api/v1/carrier-auth/change-password')
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .send({
            oldPassword: 'WrongOldPassword',
            newPassword: 'NewValidPassword123!',
          })
          .expect(401);
      });
    });
  });

  describe('Dashboard', () => {
    describe('GET /api/v1/carrier-dashboard/stats', () => {
      it('should get dashboard statistics', () => {
        return request(app.getHttpServer())
          .get('/api/v1/carrier-dashboard/stats')
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .expect(200)
          .expect((res: any) => {
            expect(res.body).toHaveProperty('totalBookings');
            expect(res.body).toHaveProperty('pendingBookings');
            expect(res.body).toHaveProperty('acceptedBookings');
            expect(res.body).toHaveProperty('rejectedBookings');
            expect(res.body).toHaveProperty('acceptanceRate');
            expect(res.body).toHaveProperty('totalRevenue');
            expect(res.body.totalRevenue).toHaveProperty('usd');
            expect(res.body.totalRevenue).toHaveProperty('eur');
            expect(res.body).toHaveProperty('recentActivities');
            expect(Array.isArray(res.body.recentActivities)).toBe(true);
          });
      });

      it('should return 401 without auth token', () => {
        return request(app.getHttpServer()).get('/api/v1/carrier-dashboard/stats').expect(401);
      });
    });

    describe('GET /api/v1/carrier-dashboard/bookings', () => {
      it('should get paginated bookings list', () => {
        return request(app.getHttpServer())
          .get('/api/v1/carrier-dashboard/bookings')
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .query({ page: 1, limit: 10 })
          .expect(200)
          .expect((res: any) => {
            expect(res.body).toHaveProperty('data');
            expect(res.body).toHaveProperty('total');
            expect(res.body).toHaveProperty('page', 1);
            expect(res.body).toHaveProperty('limit', 10);
            expect(Array.isArray(res.body.data)).toBe(true);

            if (res.body.data.length > 0) {
              bookingId = res.body.data[0].id;
              const booking = res.body.data[0];
              expect(booking).toHaveProperty('id');
              expect(booking).toHaveProperty('origin');
              expect(booking).toHaveProperty('destination');
              expect(booking).toHaveProperty('status');
              expect(booking).toHaveProperty('priceUsd');
              expect(booking).toHaveProperty('transitDays');
            }
          });
      });

      it('should filter bookings by status', () => {
        return request(app.getHttpServer())
          .get('/api/v1/carrier-dashboard/bookings')
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .query({ status: 'PENDING' })
          .expect(200)
          .expect((res: any) => {
            expect(res.body).toHaveProperty('data');
            // All bookings should have PENDING status
            res.body.data.forEach((booking: any) => {
              expect(booking.status).toBe('PENDING');
            });
          });
      });
    });

    describe('GET /api/v1/carrier-dashboard/bookings/:id', () => {
      it('should get booking details', async () => {
        if (!bookingId) {
          return; // Skip if no bookings available
        }

        await request(app.getHttpServer())
          .get(`/api/v1/carrier-dashboard/bookings/${bookingId}`)
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .expect(200)
          .expect((res: any) => {
            expect(res.body).toHaveProperty('id', bookingId);
            expect(res.body).toHaveProperty('origin');
            expect(res.body).toHaveProperty('destination');
            expect(res.body).toHaveProperty('volumeCBM');
            expect(res.body).toHaveProperty('weightKG');
            expect(res.body).toHaveProperty('priceUSD');
            expect(res.body).toHaveProperty('status');
            expect(res.body).toHaveProperty('documents');
            expect(res.body).toHaveProperty('carrierViewedAt');
          });
      });

      it('should return 404 for non-existent booking', () => {
        return request(app.getHttpServer())
          .get('/api/v1/carrier-dashboard/bookings/non-existent-id')
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .expect(404);
      });

      it('should return 401 without auth token', () => {
        return request(app.getHttpServer())
          .get(`/api/v1/carrier-dashboard/bookings/${bookingId || 'test-id'}`)
          .expect(401);
      });
    });
  });

  describe('Booking Actions', () => {
    describe('POST /api/v1/carrier-dashboard/bookings/:id/accept', () => {
      it('should accept a pending booking', async () => {
        if (!bookingId) {
          return; // Skip if no bookings available
        }

        await request(app.getHttpServer())
          .post(`/api/v1/carrier-dashboard/bookings/${bookingId}/accept`)
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .send({
            notes: 'Accepted - ready to proceed',
          })
          .expect(200);
      });

      it('should return 401 without auth token', () => {
        return request(app.getHttpServer())
          .post(`/api/v1/carrier-dashboard/bookings/test-id/accept`)
          .send({ notes: 'Test' })
          .expect(401);
      });
    });

    describe('POST /api/v1/carrier-dashboard/bookings/:id/reject', () => {
      it('should reject a pending booking with reason', async () => {
        if (!bookingId) {
          return; // Skip if no bookings available
        }

        await request(app.getHttpServer())
          .post(`/api/v1/carrier-dashboard/bookings/${bookingId}/reject`)
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .send({
            reason: 'Capacity not available',
            notes: 'Cannot accommodate this shipment at this time',
          })
          .expect(200);
      });

      it('should return 400 without rejection reason', async () => {
        if (!bookingId) {
          return; // Skip if no bookings available
        }

        await request(app.getHttpServer())
          .post(`/api/v1/carrier-dashboard/bookings/${bookingId}/reject`)
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .send({})
          .expect(400);
      });
    });
  });

  describe('Documents', () => {
    describe('GET /api/v1/carrier-dashboard/bookings/:bookingId/documents/:documentId/download', () => {
      it('should download document with valid access', async () => {
        if (!bookingId) {
          return; // Skip if no bookings available
        }

        // First get the booking details to find a document ID
        const res = await request(app.getHttpServer())
          .get(`/api/v1/carrier-dashboard/bookings/${bookingId}`)
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .expect(200);

        if (res.body.documents && res.body.documents.length > 0) {
          const documentId = res.body.documents[0].id;

          await request(app.getHttpServer())
            .get(`/api/v1/carrier-dashboard/bookings/${bookingId}/documents/${documentId}/download`)
            .set('Authorization', `Bearer ${carrierAccessToken}`)
            .expect(200);
        }
      });

      it('should return 403 for unauthorized access to document', () => {
        return request(app.getHttpServer())
          .get('/api/v1/carrier-dashboard/bookings/other-booking/documents/test-doc/download')
          .set('Authorization', `Bearer ${carrierAccessToken}`)
          .expect(403);
      });
    });
  });

  describe('Password Reset', () => {
    describe('POST /api/v1/carrier-auth/request-password-reset', () => {
      it('should request password reset for existing carrier', () => {
        return request(app.getHttpServer())
          .post('/api/v1/carrier-auth/request-password-reset')
          .send({
            email: 'test.carrier@example.com',
          })
          .expect(200);
      });

      it('should return 401 for non-existent carrier (security)', () => {
        return request(app.getHttpServer())
          .post('/api/v1/carrier-auth/request-password-reset')
          .send({
            email: 'nonexistent@example.com',
          })
          .expect(401);
      });
    });
  });
});
