/**
 * AnnotationRepository Unit Tests
 * Verifies annotation query shaping and helper methods by mocking the PostgreSQL
 * pool used by the repository layer.
 */
const AnnotationRepository = require('../../../repositories/AnnotationRepository');
const { Pool } = require('pg');

describe('AnnotationRepository - Unit Tests', () => {
    let pool;
    let repo;

    beforeAll(() => {
        // Mock pool for unit tests
        pool = {
            query: jest.fn()
        };
        repo = new AnnotationRepository(pool);
    });

    beforeEach(() => {
        jest.clearAllMocks();
    });

    describe('findAllAnnotations', () => {
        it('should query all annotations with proper structure', async () => {
            const mockRows = [
                {
                    annotationId: 'ann-1',
                    atlasId: 'atlas-1',
                    atlasNameCs: 'Atlas CS',
                    atlasNameEn: 'Atlas EN',
                    modelLabel: 'model-1',
                    fileHash: 'hash123',
                    annotator: 'John',
                    lastUpdated: new Date(),
                    isChecked: false,
                    filledTraitsCount: 5,
                    totalTraitsInAtlas: 10
                }
            ];
            pool.query.mockResolvedValue({ rows: mockRows });

            const result = await repo.findAllAnnotations();

            expect(result).toEqual(mockRows);
            expect(pool.query).toHaveBeenCalled();
        });

        it('should return empty array when no annotations exist', async () => {
            pool.query.mockResolvedValue({ rows: [] });

            const result = await repo.findAllAnnotations();

            expect(result).toEqual([]);
        });
    });

    describe('findAnnotationDetail', () => {
        it('should retrieve annotation detail by id', async () => {
            const mockRows = [
                {
                    annotationId: 'ann-1',
                    atlasId: 'atlas-1',
                    modelId: 'model-1',
                    trait_id: 'trait-1',
                    selected_label_cs: 'Možnost',
                    selected_label_en: 'Option'
                }
            ];
            pool.query.mockResolvedValue({ rows: mockRows });

            const result = await repo.findAnnotationDetail('ann-1');

            expect(result).toEqual(mockRows);
            expect(pool.query).toHaveBeenCalledWith(
                expect.stringContaining('SELECT'),
                ['ann-1']
            );
        });
    });

    describe('deleteAnnotation', () => {
        it('should delete annotation by id', async () => {
            pool.query.mockResolvedValue({ rowCount: 1 });

            await repo.deleteAnnotation('ann-1');

            expect(pool.query).toHaveBeenCalledWith(
                expect.stringContaining('DELETE'),
                expect.arrayContaining(['ann-1'])
            );
        });
    });

    describe('countModelReferences', () => {
        it('should count references to a model', async () => {
            pool.query.mockResolvedValue({ rows: [{ count: '3' }] });

            const result = await repo.countModelReferences('model-1');

            expect(result).toBe(3);
        });

        it('should return 0 when model has no references', async () => {
            pool.query.mockResolvedValue({ rows: [{ count: '0' }] });

            const result = await repo.countModelReferences('model-nope');

            expect(result).toBe(0);
        });
    });

    describe('upsertModelInTransaction', () => {
        it('should insert or update model and return id', async () => {
            const mockClient = {
                query: jest.fn()
            };
            // Simulate insert/update returning a new ID
            mockClient.query.mockResolvedValueOnce({ rows: [{ id: 'new-model-id' }] });

            const result = await repo.upsertModelInTransaction(mockClient, {
                modelId: 'test-model',
                fileHash: 'hash123',
                modelPath: '/path/to/model.obj',
                mtlPath: '/path/to/model.mtl',
                texturePath: '/path/to/texture.jpg'
            });

            expect(result).toBe('new-model-id');
            expect(mockClient.query).toHaveBeenCalledTimes(1);
        });

        it('should return existing model id when it already exists', async () => {
            const mockClient = {
                query: jest.fn()
            };
            mockClient.query.mockResolvedValueOnce({ rows: [{ id: 'existing-id' }] });

            const result = await repo.upsertModelInTransaction(mockClient, {
                modelId: 'test-model',
                fileHash: 'hash123'
            });

            expect(result).toBe('existing-id');
        });
    });
});