import { promises as fs } from 'node:fs';
import path from 'node:path';
import type { ExportManifest, GenSession } from './types';

const ROOT = path.join(process.cwd(), 'data');
const SESS_DIR = path.join(ROOT, 'sessions');
const SEL_DIR = path.join(ROOT, 'selected');
const REF_DIR = path.join(ROOT, 'refs');
const GEN_DIR = path.join(ROOT, 'generated');
const PACK_DIR = path.join(ROOT, 'packs');
const EXPORT_DIR = path.join(ROOT, 'exports');

async function ensureDirs() {
  await Promise.all([SESS_DIR, SEL_DIR, REF_DIR, GEN_DIR, PACK_DIR, EXPORT_DIR].map(d => fs.mkdir(d, { recursive: true })));
}

export async function saveSession(s: GenSession) {
  await ensureDirs();
  await fs.writeFile(path.join(SESS_DIR, `${s.id}.json`), JSON.stringify(s, null, 2), 'utf-8');
}

export async function loadSession(id: string): Promise<GenSession | null> {
  try {
    const raw = await fs.readFile(path.join(SESS_DIR, `${id}.json`), 'utf-8');
    return JSON.parse(raw);
  } catch {
    return null;
  }
}

export async function listSessions(): Promise<GenSession[]> {
  await ensureDirs();
  const files = await fs.readdir(SESS_DIR);
  const all = await Promise.all(
    files.filter(f => f.endsWith('.json')).map(async f => {
      const raw = await fs.readFile(path.join(SESS_DIR, f), 'utf-8');
      return JSON.parse(raw) as GenSession;
    })
  );
  return all.sort((a, b) => b.createdAt - a.createdAt);
}

function extFromMime(mime: string): string {
  if (mime.includes('jpeg')) return 'jpg';
  if (mime.includes('svg')) return 'svg';
  if (mime.includes('png')) return 'png';
  if (mime.includes('webp')) return 'webp';
  return 'bin';
}

export async function saveGeneratedImage(sessionId: string, imageId: string, dataUrl: string): Promise<string> {
  await ensureDirs();
  const m = dataUrl.match(/^data:([^;]+);base64,(.+)$/);
  if (!m) throw new Error('Invalid data URL');
  const ext = extFromMime(m[1]);
  const file = path.join(GEN_DIR, `${sessionId}_${imageId}.${ext}`);
  await fs.writeFile(file, Buffer.from(m[2], 'base64'));
  return `/api/img/generated/${sessionId}_${imageId}.${ext}`;
}

export async function savePackImage(packId: string, assetId: string, dataUrl: string): Promise<string> {
  await ensureDirs();
  const m = dataUrl.match(/^data:([^;]+);base64,(.+)$/);
  if (!m) throw new Error('Invalid data URL');
  const ext = extFromMime(m[1]);
  const file = path.join(PACK_DIR, `${packId}_${assetId}.${ext}`);
  await fs.writeFile(file, Buffer.from(m[2], 'base64'));
  return `/api/img/packs/${packId}_${assetId}.${ext}`;
}

export async function copyToSelected(sessionId: string, imageId: string, srcUrl: string): Promise<string> {
  await ensureDirs();
  // srcUrl 形如 /api/img/generated/xxx.png
  const match = srcUrl.match(/\/api\/img\/generated\/(.+)$/);
  if (!match) return srcUrl;
  const filename = match[1];
  const src = path.join(GEN_DIR, filename);
  const dst = path.join(SEL_DIR, filename);
  await fs.copyFile(src, dst);
  return `/api/img/selected/${filename}`;
}

export async function readImageFile(bucket: 'generated' | 'selected' | 'refs' | 'packs', filename: string): Promise<{ buf: Buffer; type: string } | null> {
  try {
    const dir = bucket === 'generated' ? GEN_DIR
      : bucket === 'selected' ? SEL_DIR
        : bucket === 'refs' ? REF_DIR
          : PACK_DIR;
    const buf = await fs.readFile(path.join(dir, filename));
    const ext = path.extname(filename).slice(1).toLowerCase();
    const type = ext === 'jpg' ? 'image/jpeg'
      : ext === 'svg' ? 'image/svg+xml'
      : `image/${ext}`;
    return { buf, type };
  } catch {
    return null;
  }
}

export async function saveRefImage(sessionId: string, idx: number, dataUrl: string): Promise<string> {
  await ensureDirs();
  const m = dataUrl.match(/^data:([^;]+);base64,(.+)$/);
  if (!m) throw new Error('Invalid ref data URL');
  const ext = extFromMime(m[1]);
  const file = path.join(REF_DIR, `${sessionId}_ref${idx}.${ext}`);
  await fs.writeFile(file, Buffer.from(m[2], 'base64'));
  return `/api/img/refs/${sessionId}_ref${idx}.${ext}`;
}

export async function saveExportManifest(manifest: ExportManifest): Promise<string> {
  await ensureDirs();
  const filename = `${manifest.sessionId}_${manifest.packKind}_${manifest.version}_manifest.json`;
  await fs.writeFile(path.join(EXPORT_DIR, filename), JSON.stringify(manifest, null, 2), 'utf-8');
  return `/api/export/${filename}`;
}
