import { randomUUID } from 'node:crypto';
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
import path from 'node:path';

const EMPTY_DB = {
  version: 1,
  entities: { Product: [], Order: [], Record: [] },
  secrets: {},
  settings: {},
  approvals: [],
  audit: [],
};

export class JsonStore {
  constructor(dataDir) {
    this.dataDir = dataDir;
    this.file = path.join(dataDir, 'shire3d.json');
    this.data = structuredClone(EMPTY_DB);
    this.writeQueue = Promise.resolve();
  }

  async init() {
    await mkdir(this.dataDir, { recursive: true });
    try {
      const parsed = JSON.parse(await readFile(this.file, 'utf8'));
      this.data = {
        ...structuredClone(EMPTY_DB),
        ...parsed,
        entities: { ...EMPTY_DB.entities, ...(parsed.entities || {}) },
      };
    } catch (error) {
      if (error.code !== 'ENOENT') throw error;
      await this.save();
    }
  }

  async save() {
    this.writeQueue = this.writeQueue.then(async () => {
      const temp = `${this.file}.tmp`;
      await writeFile(temp, `${JSON.stringify(this.data, null, 2)}\n`, { mode: 0o600 });
      await rename(temp, this.file);
    });
    return this.writeQueue;
  }

  list(entity) {
    return structuredClone(this.data.entities[entity] || []);
  }

  find(entity, id) {
    return structuredClone((this.data.entities[entity] || []).find(item => item.id === id) || null);
  }

  async create(entity, value) {
    const now = new Date().toISOString();
    const record = { ...value, id: randomUUID(), created_date: now, updated_date: now };
    this.data.entities[entity].push(record);
    await this.save();
    return structuredClone(record);
  }

  async update(entity, id, changes) {
    const records = this.data.entities[entity] || [];
    const index = records.findIndex(item => item.id === id);
    if (index < 0) return null;
    records[index] = { ...records[index], ...changes, id, updated_date: new Date().toISOString() };
    await this.save();
    return structuredClone(records[index]);
  }

  async remove(entity, id) {
    const records = this.data.entities[entity] || [];
    const index = records.findIndex(item => item.id === id);
    if (index < 0) return false;
    records.splice(index, 1);
    await this.save();
    return true;
  }

  async setSecret(name, encryptedValue) {
    this.data.secrets[name] = encryptedValue;
    await this.save();
  }

  getSecret(name) { return structuredClone(this.data.secrets[name] || null); }

  async deleteSecret(name) {
    delete this.data.secrets[name];
    await this.save();
  }

  async setSetting(name, value) {
    this.data.settings[name] = value;
    await this.save();
  }

  getSetting(name) { return structuredClone(this.data.settings[name]); }

  async deleteSetting(name) {
    delete this.data.settings[name];
    await this.save();
  }

  async recordApproval(action, details) {
    const record = { id: randomUUID(), action, details, approved_at: new Date().toISOString() };
    this.data.approvals.unshift(record);
    this.data.approvals = this.data.approvals.slice(0, 1000);
    await this.save();
    return record;
  }

  async audit(action, outcome, details = {}) {
    this.data.audit.unshift({ id: randomUUID(), action, outcome, details, at: new Date().toISOString() });
    this.data.audit = this.data.audit.slice(0, 2000);
    await this.save();
  }
}

