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

describe('Activity Tracking (e2e)', () => {
  let app: INestApplication;
  let dataSource: DataSource;

  // Test user and auth
  const testUser = {
    email: `test-tracking-${Date.now()}@example.com`,
    password: 'SecurePass123!',
    name: 'Test Parent',
    deviceInfo: {
      deviceId: 'test-device-tracking',
      platform: 'ios',
      model: 'iPhone 14',
      osVersion: '17.0',
    },
  };

  let accessToken: string;
  let userId: string;
  let familyId: string;
  let childId: string;
  let activityId: string;

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

    app = moduleFixture.createNestApplication();

    app.useGlobalPipes(
      new ValidationPipe({
        whitelist: true,
        forbidNonWhitelisted: true,
        transform: true,
      }),
    );

    await app.init();

    dataSource = app.get(DataSource);

    // Register user and get auth token
    const registerRes = await request(app.getHttpServer())
      .post('/api/v1/auth/register')
      .send(testUser);

    accessToken = registerRes.body.data.tokens.accessToken;
    userId = registerRes.body.data.user.id;
    familyId = registerRes.body.data.family.id;

    // Create a child for tracking activities
    const childRes = await request(app.getHttpServer())
      .post(`/api/v1/children?familyId=${familyId}`)
      .set('Authorization', `Bearer ${accessToken}`)
      .send({
        name: 'Emma',
        birthDate: '2023-06-15',
        gender: 'female',
      });

    childId = childRes.body.data.child.id;
  });

  afterAll(async () => {
    // Cleanup
    if (activityId) {
      await dataSource.query('DELETE FROM activities WHERE id = $1', [
        activityId,
      ]);
    }
    if (childId) {
      await dataSource.query('DELETE FROM children WHERE id = $1', [childId]);
    }
    if (userId) {
      await dataSource.query('DELETE FROM refresh_tokens WHERE user_id = $1', [
        userId,
      ]);
      await dataSource.query('DELETE FROM device_registry WHERE user_id = $1', [
        userId,
      ]);
      await dataSource.query('DELETE FROM family_members WHERE user_id = $1', [
        userId,
      ]);
    }
    if (familyId) {
      await dataSource.query('DELETE FROM families WHERE id = $1', [familyId]);
    }
    if (userId) {
      await dataSource.query('DELETE FROM users WHERE id = $1', [userId]);
    }

    await app.close();
  });

  describe('POST /api/v1/activities', () => {
    it('should create an activity', () => {
      return request(app.getHttpServer())
        .post(`/api/v1/activities?childId=${childId}`)
        .set('Authorization', `Bearer ${accessToken}`)
        .send({
          type: 'feeding',
          startedAt: '2025-09-30T12:00:00Z',
          endedAt: '2025-09-30T12:30:00Z',
          notes: 'Ate well',
          metadata: {
            amount: '120ml',
            type: 'bottle',
          },
        })
        .expect(201)
        .expect((res) => {
          expect(res.body.success).toBe(true);
          expect(res.body.data).toHaveProperty('activity');
          expect(res.body.data.activity.type).toBe('feeding');
          expect(res.body.data.activity.childId).toBe(childId);
          expect(res.body.data.activity.id).toMatch(/^act_/);

          // Store for subsequent tests
          activityId = res.body.data.activity.id;
        });
    });

    it('should require authentication', () => {
      return request(app.getHttpServer())
        .post(`/api/v1/activities?childId=${childId}`)
        .send({
          type: 'feeding',
          startedAt: '2025-09-30T12:00:00Z',
        })
        .expect(401);
    });

    it('should require childId query parameter', () => {
      return request(app.getHttpServer())
        .post('/api/v1/activities')
        .set('Authorization', `Bearer ${accessToken}`)
        .send({
          type: 'feeding',
          startedAt: '2025-09-30T12:00:00Z',
        })
        .expect(201)
        .expect((res) => {
          expect(res.body.success).toBe(false);
          expect(res.body.error.code).toBe('VALIDATION_ERROR');
        });
    });

    it('should validate required fields', () => {
      return request(app.getHttpServer())
        .post(`/api/v1/activities?childId=${childId}`)
        .set('Authorization', `Bearer ${accessToken}`)
        .send({
          type: 'feeding',
          // Missing startedAt
        })
        .expect(400);
    });

    it('should validate activity type', () => {
      return request(app.getHttpServer())
        .post(`/api/v1/activities?childId=${childId}`)
        .set('Authorization', `Bearer ${accessToken}`)
        .send({
          type: 'invalid-type',
          startedAt: '2025-09-30T12:00:00Z',
        })
        .expect(400);
    });
  });

  describe('GET /api/v1/activities', () => {
    it('should get all activities for a child', () => {
      return request(app.getHttpServer())
        .get(`/api/v1/activities?childId=${childId}`)
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body.success).toBe(true);
          expect(res.body.data).toHaveProperty('activities');
          expect(Array.isArray(res.body.data.activities)).toBe(true);
          expect(res.body.data.activities.length).toBeGreaterThan(0);
          expect(res.body.data.activities[0].type).toBe('feeding');
        });
    });

    it('should filter by activity type', () => {
      return request(app.getHttpServer())
        .get(`/api/v1/activities?childId=${childId}&type=feeding`)
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body.success).toBe(true);
          expect(
            res.body.data.activities.every((a: any) => a.type === 'feeding'),
          ).toBe(true);
        });
    });

    it('should require childId query parameter', () => {
      return request(app.getHttpServer())
        .get('/api/v1/activities')
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body.success).toBe(false);
          expect(res.body.error.code).toBe('VALIDATION_ERROR');
        });
    });

    it('should require authentication', () => {
      return request(app.getHttpServer())
        .get(`/api/v1/activities?childId=${childId}`)
        .expect(401);
    });
  });

  describe('GET /api/v1/activities/:id', () => {
    it('should get a specific activity', () => {
      return request(app.getHttpServer())
        .get(`/api/v1/activities/${activityId}`)
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body.success).toBe(true);
          expect(res.body.data).toHaveProperty('activity');
          expect(res.body.data.activity.id).toBe(activityId);
          expect(res.body.data.activity.type).toBe('feeding');
        });
    });

    it('should return 404 for non-existent activity', () => {
      return request(app.getHttpServer())
        .get('/api/v1/activities/act_nonexistent')
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(404);
    });

    it('should require authentication', () => {
      return request(app.getHttpServer())
        .get(`/api/v1/activities/${activityId}`)
        .expect(401);
    });
  });

  describe('GET /api/v1/activities/daily-summary', () => {
    it('should get daily summary', () => {
      return request(app.getHttpServer())
        .get(
          `/api/v1/activities/daily-summary?childId=${childId}&date=2025-09-30`,
        )
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body.success).toBe(true);
          expect(res.body.data).toHaveProperty('date');
          expect(res.body.data).toHaveProperty('childId');
          expect(res.body.data).toHaveProperty('activities');
          expect(res.body.data).toHaveProperty('byType');
        });
    });

    it('should require childId and date', () => {
      return request(app.getHttpServer())
        .get('/api/v1/activities/daily-summary')
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body.success).toBe(false);
        });
    });
  });

  describe('PATCH /api/v1/activities/:id', () => {
    it('should update an activity', () => {
      return request(app.getHttpServer())
        .patch(`/api/v1/activities/${activityId}`)
        .set('Authorization', `Bearer ${accessToken}`)
        .send({
          notes: 'Updated notes',
          metadata: {
            amount: '150ml',
            type: 'bottle',
          },
        })
        .expect(200)
        .expect((res) => {
          expect(res.body.success).toBe(true);
          expect(res.body.data.activity.notes).toBe('Updated notes');
          expect(res.body.data.activity.metadata.amount).toBe('150ml');
        });
    });

    it('should return 404 for non-existent activity', () => {
      return request(app.getHttpServer())
        .patch('/api/v1/activities/act_nonexistent')
        .set('Authorization', `Bearer ${accessToken}`)
        .send({
          notes: 'Test',
        })
        .expect(404);
    });

    it('should require authentication', () => {
      return request(app.getHttpServer())
        .patch(`/api/v1/activities/${activityId}`)
        .send({
          notes: 'Test',
        })
        .expect(401);
    });
  });

  describe('DELETE /api/v1/activities/:id', () => {
    it('should delete an activity', async () => {
      await request(app.getHttpServer())
        .delete(`/api/v1/activities/${activityId}`)
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body.success).toBe(true);
          expect(res.body.message).toBe('Activity deleted successfully');
        });

      // Verify activity is deleted
      await request(app.getHttpServer())
        .get(`/api/v1/activities/${activityId}`)
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(404);

      // Clear activityId so cleanup doesn't try to delete again
      activityId = null;
    });

    it('should return 404 for non-existent activity', () => {
      return request(app.getHttpServer())
        .delete('/api/v1/activities/act_nonexistent')
        .set('Authorization', `Bearer ${accessToken}`)
        .expect(404);
    });

    it('should require authentication', () => {
      return request(app.getHttpServer())
        .delete(`/api/v1/activities/${activityId}`)
        .expect(401);
    });
  });
});
