import { Global, Module } from '@nestjs/common';
import {
  createMemory,
  type Memory,
  createMemoryAdapter,
  createOperatorMemoryPlugin,
  type MemoryAdapter,
  type MemoryConfig,
  type OperatorMemoryPlugin,
} from '@mosaicstack/memory';
import type { Db } from '@mosaicstack/db';
import type { StorageAdapter } from '@mosaicstack/storage';
import type { MosaicConfig } from '@mosaicstack/config';
import { MOSAIC_CONFIG } from '../config/config.module.js';
import { DB, STORAGE_ADAPTER } from '../database/database.module.js';
import { MEMORY } from './memory.tokens.js';
import { MemoryController } from './memory.controller.js';
import { EmbeddingService } from './embedding.service.js';
import { redactSensitiveContent } from '@mosaicstack/log';

export const OPERATOR_MEMORY_PLUGIN = 'OPERATOR_MEMORY_PLUGIN';

export const MEMORY_ADAPTER = 'MEMORY_ADAPTER';

function buildMemoryConfig(config: MosaicConfig, storageAdapter: StorageAdapter): MemoryConfig {
  if (config.memory.type === 'keyword') {
    return { type: 'keyword', storage: storageAdapter };
  }
  return { type: config.memory.type };
}

@Global()
@Module({
  providers: [
    {
      provide: MEMORY,
      useFactory: (db: Db): Memory => createMemory(db),
      inject: [DB],
    },
    {
      provide: MEMORY_ADAPTER,
      useFactory: (config: MosaicConfig, storageAdapter: StorageAdapter): MemoryAdapter =>
        createMemoryAdapter(buildMemoryConfig(config, storageAdapter)),
      inject: [MOSAIC_CONFIG, STORAGE_ADAPTER],
    },
    {
      provide: OPERATOR_MEMORY_PLUGIN,
      useFactory: (adapter: MemoryAdapter): OperatorMemoryPlugin | null => {
        const instanceId = process.env['MOSAIC_OPERATOR_MEMORY_INSTANCE_ID']?.trim();
        const namespace = process.env['MOSAIC_OPERATOR_MEMORY_NAMESPACE']?.trim();
        if (!instanceId || !namespace) return null;
        return createOperatorMemoryPlugin({
          adapter,
          instanceId,
          namespace,
          redact: (content) => redactSensitiveContent(content).content,
        });
      },
      inject: [MEMORY_ADAPTER],
    },
    EmbeddingService,
  ],
  controllers: [MemoryController],
  exports: [MEMORY, MEMORY_ADAPTER, OPERATOR_MEMORY_PLUGIN, EmbeddingService],
})
export class MemoryModule {}
