// Bibliothèque de portfolios : un fichier JSON par portfolio (spec §13).
import { mkdir, readdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
import { join } from 'node:path'
import { nanoid } from 'nanoid'
import type { Portfolio, PortfolioSummary } from '~~/types'

function portfoliosDir(): string {
  return join(useRuntimeConfig().dataDir, 'portfolios')
}

function pathFor(id: string): string {
  if (!/^[\w-]+$/.test(id)) {
    throw createError({ statusCode: 400, statusMessage: 'Identifiant invalide' })
  }
  return join(portfoliosDir(), `${id}.json`)
}

export async function listPortfolios(): Promise<PortfolioSummary[]> {
  let files: string[] = []
  try {
    files = (await readdir(portfoliosDir())).filter(f => f.endsWith('.json'))
  } catch {
    return []
  }
  const summaries: PortfolioSummary[] = []
  for (const f of files) {
    try {
      const p = JSON.parse(await readFile(join(portfoliosDir(), f), 'utf8')) as Portfolio
      summaries.push({
        id: p.id,
        name: p.name,
        pageCount: p.pages.length,
        updatedAt: p.updatedAt,
        createdAt: p.createdAt,
        coverTitle: p.cover?.title ?? p.name,
        hasPdf: Boolean(p.lastExport),
        // « À jour » : la génération aligne lastExport.at sur updatedAt ; toute
        // édition ultérieure retouche updatedAt (> lastExport.at) → périmé.
        pdfCurrent: Boolean(p.lastExport && p.updatedAt <= p.lastExport.at),
        exportFileName: p.lastExport?.fileName,
        publicShare: Boolean(p.publicShare),
      })
    } catch {
      // fichier corrompu : ignoré de la liste
    }
  }
  summaries.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))
  return summaries
}

export async function getPortfolio(id: string): Promise<Portfolio | null> {
  try {
    return JSON.parse(await readFile(pathFor(id), 'utf8')) as Portfolio
  } catch {
    return null
  }
}

export async function savePortfolio(portfolio: Portfolio, touch = true): Promise<Portfolio> {
  // touch=false : conserve updatedAt tel quel (utilisé après génération pour
  // aligner updatedAt sur lastExport.at et marquer le PDF « à jour »).
  if (touch) portfolio.updatedAt = new Date().toISOString()
  await mkdir(portfoliosDir(), { recursive: true })
  // Écriture ATOMIQUE (fichier temporaire + rename) : l'autosave de l'éditeur
  // peut écrire pendant que la génération PDF relit le portfolio via /print.
  // Un writeFile en place tronque le fichier → lecture concurrente = JSON
  // partiel → getPortfolio renvoie null → rendu print en échec. Le rename est
  // atomique sur le même volume : les lecteurs voient toujours l'ancien OU le
  // nouveau fichier complet, jamais un état intermédiaire.
  const dest = pathFor(portfolio.id)
  const tmp = `${dest}.tmp-${nanoid(6)}`
  await writeFile(tmp, JSON.stringify(portfolio, null, 2))
  await rename(tmp, dest)
  return portfolio
}

export async function createPortfolio(name: string): Promise<Portfolio> {
  const now = new Date().toISOString()
  const portfolio: Portfolio = {
    id: nanoid(10),
    name: name || 'Portfolio sans titre',
    cover: {
      title: name || 'Portfolio',
      subtitle: '',
      recipient: '',
      background: { mode: 'white' },
    },
    pages: [{ kind: 'cover', id: nanoid(8), background: { mode: 'white' } }],
    createdAt: now,
    updatedAt: now,
  }
  return await savePortfolio(portfolio)
}

export async function duplicatePortfolio(id: string): Promise<Portfolio | null> {
  const source = await getPortfolio(id)
  if (!source) return null
  const now = new Date().toISOString()
  const copy: Portfolio = {
    ...source,
    id: nanoid(10),
    name: `${source.name} (copie)`,
    createdAt: now,
    updatedAt: now,
    frozenContent: undefined,
    lastExport: undefined,
  }
  return await savePortfolio(copy)
}

export async function deletePortfolio(id: string): Promise<void> {
  await rm(pathFor(id), { force: true })
}
