import { json } from '@remix-run/node';
import fs from 'node:fs/promises';
import path from 'node:path';
import { authenticate } from '../shopify.server.js';

// Backups der Preis- und Tag-Änderungen als einzelne JSON-Dateien auf dem Server.
// Je Speicherung eine Datei; Dateien älter als RETENTION_DAYS werden automatisch gelöscht.
// Der Ordner liegt bewusst außerhalb des App-Ordners (wie die Datenbank), damit ein neuer Build ihn nicht berührt.
const DIR = process.env.PRICE_BACKUP_DIR || '/home/service8/data/price-backups';
const RETENTION_DAYS = Number(process.env.PRICE_BACKUP_RETENTION_DAYS) || 90;
const MAX_BYTES = 8 * 1024 * 1024;
const SOURCES = ['manual', 'pricelist', 'restore'];
const FILE_RE = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(\d{3})Z-(manual|pricelist|restore)\.json$/;
const ISO_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;

const fileNameFor = (id: string, src: string): string => `${id.replace(/[-:.]/g, '')}-${src}.json`;

const dateFromFile = (name: string): number | null => {
  const m = name.match(FILE_RE);
  if (!m) return null;
  return Date.parse(`${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:${m[6]}.${m[7]}Z`);
};

async function ensureDir(): Promise<void> {
  await fs.mkdir(DIR, { recursive: true, mode: 0o700 });
}

/** Löscht Backup-Dateien, die älter als die Aufbewahrungsfrist sind. */
async function cleanup(): Promise<number> {
  const cutoff = Date.now() - RETENTION_DAYS * 24 * 3600 * 1000;
  let removed = 0;
  for (const name of await fs.readdir(DIR)) {
    const t = dateFromFile(name);
    if (t !== null && t < cutoff) {
      await fs.unlink(path.join(DIR, name)).catch(() => undefined);
      removed++;
    }
  }
  return removed;
}

export async function loader({ request }: { request: Request }) {
  await authenticate.admin(request);
  try {
    await ensureDir();
    await cleanup();
    const entries: unknown[] = [];
    for (const name of (await fs.readdir(DIR)).sort().reverse()) {
      if (!FILE_RE.test(name)) continue;
      try {
        entries.push(JSON.parse(await fs.readFile(path.join(DIR, name), 'utf8')));
      } catch {
        /* beschädigte Datei überspringen */
      }
    }
    return json({ entries, retentionDays: RETENTION_DAYS });
  } catch (e: any) {
    return json({ error: `Backups konnten nicht gelesen werden: ${e?.message || 'Fehler'}` }, { status: 500 });
  }
}

export async function action({ request }: { request: Request }) {
  await authenticate.admin(request);
  if (request.method !== 'POST') return json({ error: 'Methode nicht erlaubt' }, { status: 405 });
  try {
    const text = await request.text();
    if (text.length > MAX_BYTES) return json({ error: 'Backup zu groß' }, { status: 413 });
    const entry = JSON.parse(text);
    if (
      !entry ||
      typeof entry.id !== 'string' ||
      !ISO_RE.test(entry.id) ||
      !SOURCES.includes(entry.src) ||
      !Array.isArray(entry.items) ||
      !Array.isArray(entry.tags)
    ) {
      return json({ error: 'Ungültiges Backup-Format' }, { status: 400 });
    }
    await ensureDir();
    const file = path.join(DIR, fileNameFor(entry.id, entry.src));
    const tmp = `${file}.tmp`;
    await fs.writeFile(tmp, JSON.stringify(entry), { mode: 0o600 });
    await fs.rename(tmp, file); // atomar: entweder komplette Datei oder keine
    await cleanup();
    return json({ ok: true });
  } catch (e: any) {
    return json({ error: `Backup konnte nicht gespeichert werden: ${e?.message || 'Fehler'}` }, { status: 500 });
  }
}
