import { resolve } from 'path';
import { config } from '../../utils/config.js';
import { encrypt, decrypt } from '../../utils/crypto.js';
import { createModuleLogger } from '../../utils/logger.js';
import { atomicWriteJSON, readJSON, ensureDir } from './file-ops.js';

const log = createModuleLogger('encrypted-store');

interface EncryptedEntry {
  encrypted: string;
  createdAt: string;
  updatedAt: string;
}

interface EncryptedStoreData {
  version: 1;
  keys: Record<string, EncryptedEntry>;
}

export class EncryptedKeyStore {
  private filePath: string;
  private masterKey: string;

  constructor(dataDir?: string, masterKey?: string) {
    const dir = dataDir || config.dataDir;
    this.filePath = resolve(dir, 'config', 'api-keys.enc.json');
    this.masterKey = masterKey ?? config.encryptionKey;
  }

  async init(): Promise<void> {
    await ensureDir(resolve(this.filePath, '..'));
    const existing = await readJSON<EncryptedStoreData>(this.filePath);
    if (!existing) {
      await atomicWriteJSON(this.filePath, { version: 1, keys: {} });
    }
  }

  async setKey(name: string, value: string): Promise<void> {
    if (!this.masterKey) throw new Error('ENCRYPTION_KEY is not configured');
    const store = await this.loadStore();
    const now = new Date().toISOString();
    store.keys[name] = {
      encrypted: encrypt(value, this.masterKey),
      createdAt: store.keys[name]?.createdAt || now,
      updatedAt: now,
    };
    await atomicWriteJSON(this.filePath, store);
    log.info({ name }, 'Key saved');
  }

  async getKey(name: string): Promise<string | null> {
    if (!this.masterKey) throw new Error('ENCRYPTION_KEY is not configured');
    const store = await this.loadStore();
    const entry = store.keys[name];
    if (!entry) return null;
    return decrypt(entry.encrypted, this.masterKey);
  }

  async deleteKey(name: string): Promise<boolean> {
    const store = await this.loadStore();
    if (!store.keys[name]) return false;
    delete store.keys[name];
    await atomicWriteJSON(this.filePath, store);
    log.info({ name }, 'Key deleted');
    return true;
  }

  async listKeys(): Promise<Array<{ name: string; maskedValue: string; createdAt: string; updatedAt: string }>> {
    if (!this.masterKey) throw new Error('ENCRYPTION_KEY is not configured');
    const store = await this.loadStore();
    const result: Array<{ name: string; maskedValue: string; createdAt: string; updatedAt: string }> = [];
    for (const [name, entry] of Object.entries(store.keys)) {
      try {
        const value = decrypt(entry.encrypted, this.masterKey);
        const masked = value.length > 4 ? '****' + value.slice(-4) : '****';
        result.push({ name, maskedValue: masked, createdAt: entry.createdAt, updatedAt: entry.updatedAt });
      } catch {
        result.push({ name, maskedValue: '****[decrypt error]', createdAt: entry.createdAt, updatedAt: entry.updatedAt });
      }
    }
    return result;
  }

  async hasKey(name: string): Promise<boolean> {
    const store = await this.loadStore();
    return name in store.keys;
  }

  private async loadStore(): Promise<EncryptedStoreData> {
    const store = await readJSON<EncryptedStoreData>(this.filePath);
    return store || { version: 1, keys: {} };
  }
}

export const encryptedKeyStore = new EncryptedKeyStore();
