import { describe, expect, it, beforeAll, afterAll } from 'vitest';
import { qualifyTable } from './test-db-config.js';
import { ensureFinancialEntity, ensureTaxCategoryForEntity, setAdminEntity } from './seed-helpers.js';
import { EntityValidationError } from './seed-errors.js';
import { TestDatabase } from './db-setup.js';

describe('ensureTaxCategoryForEntity', () => {
  let db: TestDatabase;

  beforeAll(async () => {
    db = new TestDatabase();
    await db.connect();
  });

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

  it('should create tax category on first call', async () =>
    db.withTransaction(async client => {
      const ownerId = await setAdminEntity(client);

      // Create financial entity
      const { id: entityId } = await ensureFinancialEntity(client, {
        name: 'VAT Category',
        type: 'tax_category',
        ownerId,
      });

      // Create tax category
      await ensureTaxCategoryForEntity(client, entityId, {ownerId});

      // Verify tax category exists
      const result = await client.query(
        `SELECT id FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
        [entityId],
      );

      expect(result.rows).toHaveLength(1);
      expect(result.rows[0].id).toBe(entityId);
    }));

  it('should be idempotent (no-op on repeated calls)', async () =>
    db.withTransaction(async client => {
      const ownerId = await setAdminEntity(client);
      
      // Create financial entity
      const { id: entityId } = await ensureFinancialEntity(client, {
        name: 'Income Tax',
        type: 'tax_category',
        ownerId,
      });

      // Create tax category twice
      await ensureTaxCategoryForEntity(client, entityId, {ownerId});
      await ensureTaxCategoryForEntity(client, entityId, {ownerId});

      // Verify only one row exists
      const result = await client.query(
        `SELECT COUNT(*) as count FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
        [entityId],
      );

      expect(result.rows[0].count).toBe('1');
    }));

  it('should preserve existing values on subsequent calls', async () =>
    db.withTransaction(async client => {
      const ownerId = await setAdminEntity(client);

      // Create financial entity
      const { id: entityId } = await ensureFinancialEntity(client, {
        name: 'Expense Category',
        type: 'tax_category',
        ownerId,
      });

      // Create tax category
      await ensureTaxCategoryForEntity(client, entityId, {ownerId});

      // Get initial state
      const initialResult = await client.query(
        `SELECT * FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
        [entityId],
      );
      const initialRow = initialResult.rows[0];

      // Call again (should not modify)
      await ensureTaxCategoryForEntity(client, entityId, { sortCode: 999, ownerId });

      // Verify unchanged
      const finalResult = await client.query(
        `SELECT * FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
        [entityId],
      );
      const finalRow = finalResult.rows[0];

      expect(finalRow).toEqual(initialRow);
    }));

  it('should reject invalid UUID format', async () =>
    db.withTransaction(async client => {
      await expect(ensureTaxCategoryForEntity(client, 'not-a-uuid')).rejects.toThrow(
        EntityValidationError,
      );

      await expect(ensureTaxCategoryForEntity(client, '')).rejects.toThrow(
        EntityValidationError,
      );

      await expect(ensureTaxCategoryForEntity(client, '12345')).rejects.toThrow(
        EntityValidationError,
      );
    }));

  it('should reject non-existent financial entity', async () =>
    db.withTransaction(async client => {
      const fakeUuid = '00000000-0000-0000-0000-000000000001';

      await expect(ensureTaxCategoryForEntity(client, fakeUuid)).rejects.toThrow(
        EntityValidationError,
      );
    }));

  it('should not leak data between tests', async () =>
    db.withTransaction(async client => {
      // This test verifies transactional isolation by checking that data
      // from previous tests is not visible
      const result = await client.query(
        `SELECT COUNT(*) as count FROM ${qualifyTable('tax_categories')} WHERE id IN (SELECT id FROM ${qualifyTable('financial_entities')} WHERE name LIKE 'VAT Category' OR name LIKE 'Income Tax' OR name LIKE 'Expense Category')`,
      );

      // Due to ROLLBACK after each test, count should be 0
      expect(parseInt(result.rows[0].count)).toBe(0);
    }));

  it('should handle options parameter gracefully (future-proofing)', async () =>
    db.withTransaction(async client => {
      const ownerId = await setAdminEntity(client);
      
      // Create financial entity
      const { id: entityId } = await ensureFinancialEntity(client, {
        name: 'Category with Options',
        type: 'tax_category',
        ownerId,
      });

      // Create tax category with options
      await ensureTaxCategoryForEntity(client, entityId, { sortCode: 1000, ownerId });

      // Verify tax category exists
      const result = await client.query(
        `SELECT id FROM ${qualifyTable('tax_categories')} WHERE id = $1`,
        [entityId],
      );

      expect(result.rows).toHaveLength(1);
    }));
});
