import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync } from 'fs';
import { join, resolve } from 'path';
import { createHash, randomUUID } from 'crypto';
import { appendOmnlAudit } from './omnl-audit-log';

export type Iso20022MessageType = 'pain.001' | 'pacs.008' | 'camt.053' | 'other';

export type Iso20022Record = {
  id: string;
  messageType: Iso20022MessageType;
  receivedAt: string;
  retentionUntil: string;
  uetr?: string;
  instructionId?: string;
  settlementOrChainRef?: string;
  accountingRef?: string;
  payloadSha256: string;
  payload: string;
};

function storeDir(): string {
  const raw = process.env.OMNL_ISO20022_STORE_DIR?.trim();
  if (raw) return resolve(raw);
  const root = process.env.PROXMOX_ROOT || process.env.PHOENIX_REPO_ROOT || process.cwd();
  return resolve(root, 'config/iso20022-omnl/messages');
}

function retentionYears(): number {
  const y = parseInt(process.env.OMNL_ISO20022_RETENTION_YEARS || '10', 10);
  return Number.isFinite(y) && y > 0 ? y : 10;
}

export function iso20022RetentionUntil(fromIso?: string): string {
  const d = fromIso ? new Date(fromIso) : new Date();
  d.setFullYear(d.getFullYear() + retentionYears());
  return d.toISOString();
}

export function saveIso20022Message(input: {
  messageType: Iso20022MessageType;
  payload: string;
  uetr?: string;
  instructionId?: string;
  settlementOrChainRef?: string;
  accountingRef?: string;
}): Iso20022Record {
  const dir = storeDir();
  mkdirSync(dir, { recursive: true });
  const id = randomUUID();
  const receivedAt = new Date().toISOString();
  const payloadSha256 = createHash('sha256').update(input.payload, 'utf8').digest('hex');
  const record: Iso20022Record = {
    id,
    messageType: input.messageType,
    receivedAt,
    retentionUntil: iso20022RetentionUntil(receivedAt),
    uetr: input.uetr,
    instructionId: input.instructionId,
    settlementOrChainRef: input.settlementOrChainRef,
    accountingRef: input.accountingRef,
    payloadSha256,
    payload: input.payload,
  };
  writeFileSync(join(dir, `${id}.json`), JSON.stringify(record, null, 2), 'utf8');
  appendOmnlAudit({
    category: 'iso20022',
    action: 'store_message',
    traceId: id,
    referenceNumber: input.instructionId,
    metadata: { messageType: input.messageType, payloadSha256 },
    status: 'ok',
  });
  return record;
}

export function listIso20022Messages(limit = 50): Array<Pick<Iso20022Record, 'id' | 'messageType' | 'receivedAt' | 'instructionId' | 'accountingRef'>> {
  const dir = storeDir();
  if (!existsSync(dir)) return [];
  const files = readdirSync(dir)
    .filter((f) => f.endsWith('.json'))
    .sort()
    .reverse()
    .slice(0, limit);
  return files.map((f) => {
    const r = JSON.parse(readFileSync(join(dir, f), 'utf8')) as Iso20022Record;
    return {
      id: r.id,
      messageType: r.messageType,
      receivedAt: r.receivedAt,
      instructionId: r.instructionId,
      accountingRef: r.accountingRef,
    };
  });
}

export function getIso20022Message(id: string): Iso20022Record | null {
  const p = join(storeDir(), `${id}.json`);
  if (!existsSync(p)) return null;
  return JSON.parse(readFileSync(p, 'utf8')) as Iso20022Record;
}
