import { DataSource } from 'typeorm';
import { config } from './index.js';
import { logger } from '../shared/utils/logger.js';

// Import Auth Core Entities
import {
  Tenant,
  Company,
  User,
  Role,
  Permission,
  Session,
  PasswordReset,
} from '../modules/auth/entities/index.js';

// Import Auth Extension Entities
import {
  Group,
  ApiKey,
  TrustedDevice,
  VerificationCode,
  MfaAuditLog,
  OAuthProvider,
  OAuthUserLink,
  OAuthState,
} from '../modules/auth/entities/index.js';

// Import Core Module Entities
import { Partner } from '../modules/partners/entities/index.js';
import {
  Currency,
  CurrencyRate,
  Country,
  State,
  UomCategory,
  Uom,
  ProductCategory,
  Sequence,
  PaymentTerm,
  PaymentTermLine,
  DiscountRule,
} from '../modules/core/entities/index.js';

// Import Financial Entities
import {
  AccountType,
  Account,
  Journal,
  JournalEntry,
  JournalEntryLine,
  Invoice,
  InvoiceLine,
  Payment,
  Tax,
  FiscalYear,
  FiscalPeriod,
} from '../modules/financial/entities/index.js';

// Import Inventory Entities
import {
  Product,
  Warehouse,
  Location,
  StockQuant,
  Lot,
  Picking,
  StockMove,
  StockLevel,
  StockMovement,
  InventoryCount,
  InventoryCountLine,
  InventoryAdjustment,
  InventoryAdjustmentLine,
  TransferOrder,
  TransferOrderLine,
  StockValuationLayer,
} from '../modules/inventory/entities/index.js';

// Import Fiscal Entities
import {
  TaxCategory,
  FiscalRegime,
  CfdiUse,
  PaymentMethod,
  PaymentType,
  WithholdingType,
} from '../modules/fiscal/entities/index.js';

// Import Settings Entities
import {
  SystemSetting,
  PlanSetting,
  TenantSetting,
  UserPreference,
} from '../modules/settings/entities/index.js';

/**
 * TypeORM DataSource configuration
 *
 * Configurado para coexistir con el pool pg existente.
 * Permite migración gradual a entities sin romper el código actual.
 */
export const AppDataSource = new DataSource({
  type: 'postgres',
  host: config.database.host,
  port: config.database.port,
  username: config.database.user,
  password: config.database.password,
  database: config.database.name,

  // Schema por defecto para entities de autenticación
  schema: 'auth',

  // Entities registradas
  entities: [
    // Auth Core Entities
    Tenant,
    Company,
    User,
    Role,
    Permission,
    Session,
    PasswordReset,
    // Auth Extension Entities
    Group,
    ApiKey,
    TrustedDevice,
    VerificationCode,
    MfaAuditLog,
    OAuthProvider,
    OAuthUserLink,
    OAuthState,
    // Core Module Entities
    Partner,
    Currency,
    CurrencyRate,
    Country,
    State,
    UomCategory,
    Uom,
    ProductCategory,
    Sequence,
    PaymentTerm,
    PaymentTermLine,
    DiscountRule,
    // Financial Entities
    AccountType,
    Account,
    Journal,
    JournalEntry,
    JournalEntryLine,
    Invoice,
    InvoiceLine,
    Payment,
    Tax,
    FiscalYear,
    FiscalPeriod,
    // Inventory Entities
    Product,
    Warehouse,
    Location,
    StockQuant,
    Lot,
    Picking,
    StockMove,
    StockLevel,
    StockMovement,
    InventoryCount,
    InventoryCountLine,
    InventoryAdjustment,
    InventoryAdjustmentLine,
    TransferOrder,
    TransferOrderLine,
    StockValuationLayer,
    // Fiscal Entities
    TaxCategory,
    FiscalRegime,
    CfdiUse,
    PaymentMethod,
    PaymentType,
    WithholdingType,
    // Settings Entities
    SystemSetting,
    PlanSetting,
    TenantSetting,
    UserPreference,
  ],

  // Directorios de migraciones (para uso futuro)
  migrations: [
    // 'src/database/migrations/*.ts'
  ],

  // Directorios de subscribers (para uso futuro)
  subscribers: [
    // 'src/database/subscribers/*.ts'
  ],

  // NO usar synchronize en producción - usamos DDL manual
  synchronize: false,

  // Logging: habilitado en desarrollo, solo errores en producción
  logging: config.env === 'development' ? ['query', 'error', 'warn'] : ['error'],

  // Log queries lentas (> 1000ms)
  maxQueryExecutionTime: 1000,

  // Pool de conexiones (configuración conservadora para no interferir con pool pg)
  extra: {
    max: 10, // Menor que el pool pg (20) para no competir por conexiones
    min: 2,
    idleTimeoutMillis: 30000,
    connectionTimeoutMillis: 2000,
  },

  // Cache de queries (opcional, se puede habilitar después)
  cache: false,
});

/**
 * Inicializa la conexión TypeORM
 * @returns Promise<boolean> - true si la conexión fue exitosa
 */
export async function initializeTypeORM(): Promise<boolean> {
  try {
    if (!AppDataSource.isInitialized) {
      await AppDataSource.initialize();
      logger.info('TypeORM DataSource initialized successfully', {
        database: config.database.name,
        schema: 'auth',
        host: config.database.host,
      });
      return true;
    }
    logger.warn('TypeORM DataSource already initialized');
    return true;
  } catch (error) {
    logger.error('Failed to initialize TypeORM DataSource', {
      error: (error as Error).message,
      stack: (error as Error).stack,
    });
    return false;
  }
}

/**
 * Cierra la conexión TypeORM
 */
export async function closeTypeORM(): Promise<void> {
  try {
    if (AppDataSource.isInitialized) {
      await AppDataSource.destroy();
      logger.info('TypeORM DataSource closed');
    }
  } catch (error) {
    logger.error('Error closing TypeORM DataSource', {
      error: (error as Error).message,
    });
  }
}

/**
 * Obtiene el estado de la conexión TypeORM
 */
export function isTypeORMConnected(): boolean {
  return AppDataSource.isInitialized;
}
