import { Test, TestingModule } from '@nestjs/testing';
import { ConfigModule } from '@nestjs/config';
import { PrismaService } from '../../src/infrastructure/persistence/prisma/prisma.service';
import { ReportDefinitionRepository } from '../../src/infrastructure/persistence/repositories/report-definition.repository.impl';
import { ReportDefinition } from '../../src/domain/aggregates/report-definition';
import { ReportType, OutputFormat, ReportSchedule } from '../../src/domain/value-objects';

describe('ReportDefinitionRepository Integration', () => {
  let module: TestingModule;
  let repository: ReportDefinitionRepository;
  let prisma: PrismaService;

  beforeAll(async () => {
    module = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath: ['.env.test', '.env'],
        }),
      ],
      providers: [PrismaService, ReportDefinitionRepository],
    }).compile();

    repository = module.get<ReportDefinitionRepository>(ReportDefinitionRepository);
    prisma = module.get<PrismaService>(PrismaService);
  });

  afterAll(async () => {
    await prisma.$disconnect();
    await module.close();
  });

  beforeEach(async () => {
    // Clean up test data
    await prisma.reportDefinition.deleteMany({
      where: { reportCode: { startsWith: 'TEST_' } },
    });
  });

  describe('save', () => {
    it('should create a new report definition', async () => {
      const definition = ReportDefinition.create({
        reportType: ReportType.LEADERBOARD_REPORT,
        reportName: 'Test Report',
        reportCode: 'TEST_REPO_001',
        description: 'Integration test report',
        outputFormats: [OutputFormat.EXCEL, OutputFormat.CSV],
      });

      const saved = await repository.save(definition);

      expect(saved.id).toBeDefined();
      expect(saved.reportCode).toBe('TEST_REPO_001');
      expect(saved.reportName).toBe('Test Report');
      expect(saved.outputFormats).toContain(OutputFormat.EXCEL);
    });

    it('should update an existing report definition', async () => {
      // Create first
      const definition = ReportDefinition.create({
        reportType: ReportType.PLANTING_REPORT,
        reportName: 'Original Name',
        reportCode: 'TEST_REPO_002',
      });

      const saved = await repository.save(definition);

      // Update
      saved.updateName('Updated Name');
      saved.updateDescription('Updated description');
      const updated = await repository.save(saved);

      expect(updated.reportName).toBe('Updated Name');
      expect(updated.description).toBe('Updated description');
    });
  });

  describe('findByCode', () => {
    it('should find definition by code', async () => {
      const definition = ReportDefinition.create({
        reportType: ReportType.COMMUNITY_REPORT,
        reportName: 'Find Test',
        reportCode: 'TEST_REPO_003',
      });

      await repository.save(definition);

      const found = await repository.findByCode('TEST_REPO_003');

      expect(found).not.toBeNull();
      expect(found?.reportName).toBe('Find Test');
    });

    it('should return null for non-existent code', async () => {
      const found = await repository.findByCode('NON_EXISTENT_CODE');
      expect(found).toBeNull();
    });
  });

  describe('findActive', () => {
    it('should find all active definitions', async () => {
      // Create active definition
      const active = ReportDefinition.create({
        reportType: ReportType.LEADERBOARD_REPORT,
        reportName: 'Active Report',
        reportCode: 'TEST_REPO_004',
      });
      await repository.save(active);

      // Create inactive definition
      const inactive = ReportDefinition.create({
        reportType: ReportType.LEADERBOARD_REPORT,
        reportName: 'Inactive Report',
        reportCode: 'TEST_REPO_005',
      });
      inactive.deactivate();
      await repository.save(inactive);

      const activeDefinitions = await repository.findActive();
      const testDefinitions = activeDefinitions.filter(d => d.reportCode.startsWith('TEST_'));

      expect(testDefinitions.length).toBe(1);
      expect(testDefinitions[0].reportCode).toBe('TEST_REPO_004');
    });
  });

  describe('findScheduled', () => {
    it('should find scheduled definitions', async () => {
      // Create scheduled definition
      const scheduled = ReportDefinition.create({
        reportType: ReportType.PLANTING_REPORT,
        reportName: 'Scheduled Report',
        reportCode: 'TEST_REPO_006',
        schedule: ReportSchedule.daily(1, 0),
      });
      await repository.save(scheduled);

      // Create non-scheduled definition
      const nonScheduled = ReportDefinition.create({
        reportType: ReportType.PLANTING_REPORT,
        reportName: 'Non-Scheduled Report',
        reportCode: 'TEST_REPO_007',
      });
      await repository.save(nonScheduled);

      const scheduledDefinitions = await repository.findScheduled();
      const testDefinitions = scheduledDefinitions.filter(d => d.reportCode.startsWith('TEST_'));

      expect(testDefinitions.length).toBe(1);
      expect(testDefinitions[0].reportCode).toBe('TEST_REPO_006');
    });
  });

  describe('delete', () => {
    it('should delete a definition', async () => {
      const definition = ReportDefinition.create({
        reportType: ReportType.LEADERBOARD_REPORT,
        reportName: 'To Delete',
        reportCode: 'TEST_REPO_008',
      });

      const saved = await repository.save(definition);
      expect(saved.id).toBeDefined();

      await repository.delete(saved.id!);

      const found = await repository.findByCode('TEST_REPO_008');
      expect(found).toBeNull();
    });
  });
});
