const fs = require("fs");
const path = require("path");
const db = require("../db/models");
const { retentionPolicy, cutoffDate } = require("../security/dataLifecycle");

const audioDir = process.env.COACHING_AUDIO_DIR || path.join(__dirname, "../../private/coaching-sessions");

function audioFilePath(audioUrl) {
  if (!String(audioUrl || "").startsWith("/private-coaching-audio/")) {
    return null;
  }

  return path.join(audioDir, path.basename(audioUrl));
}

async function removeAudio(session) {
  const filePath = audioFilePath(session.audio_url);

  if (filePath) {
    await fs.promises.rm(filePath, { force: true });
  }

  await session.update({
    audio_url: null,
    audio_filename: null,
    audio_mime_type: null,
    audio_size: null,
  });
}

async function runRetention() {
  const policy = retentionPolicy();
  const audioSessions = await db.sessions.findAll({
    where: {
      audio_url: { [db.Sequelize.Op.ne]: null },
      session_at: { [db.Sequelize.Op.lt]: cutoffDate(policy.raw_audio_days) },
    },
  });

  for (const session of audioSessions) {
    await removeAudio(session);
  }

  const [transcriptsCleared] = await db.sessions.update(
    { transcript_notes: null },
    {
      where: {
        transcript_notes: { [db.Sequelize.Op.ne]: null },
        session_at: { [db.Sequelize.Op.lt]: cutoffDate(policy.transcript_days) },
      },
    },
  );

  const expiredSessions = await db.sessions.findAll({
    where: {
      session_at: { [db.Sequelize.Op.lt]: cutoffDate(policy.session_memory_days) },
    },
  });

  for (const session of expiredSessions) {
    const transaction = await db.sequelize.transaction();
    try {
      await removeAudio(session);
      await db.action_items.destroy({ where: { sessionId: session.id }, force: true, transaction });
      await db.prep_briefs.destroy({ where: { sessionId: session.id }, force: true, transaction });
      await session.destroy({ force: true, transaction });
      await transaction.commit();
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }

  const backupDir = process.env.COACHING_BACKUP_DIR || path.join(__dirname, "../../private/backups");
  let backupsRemoved = 0;
  if (fs.existsSync(backupDir)) {
    const backupCutoff = cutoffDate(policy.backup_expiry_days).getTime();
    const backupEntries = await fs.promises.readdir(backupDir, { withFileTypes: true });
    for (const entry of backupEntries) {
      if (!entry.isFile()) {
        continue;
      }

      const backupPath = path.join(backupDir, entry.name);
      const stat = await fs.promises.stat(backupPath);
      if (stat.mtimeMs < backupCutoff) {
        await fs.promises.rm(backupPath);
        backupsRemoved += 1;
      }
    }
  }

  console.log(JSON.stringify({
    event: "coaching_retention_complete",
    audio_removed: audioSessions.length,
    transcripts_cleared: transcriptsCleared,
    session_memories_removed: expiredSessions.length,
    backups_removed: backupsRemoved,
  }));
}

if (require.main === module) {
  runRetention()
    .then(() => db.sequelize.close())
    .catch(async (error) => {
      console.error("Coaching retention failed", error);
      await db.sequelize.close();
      process.exitCode = 1;
    });
}

module.exports = { runRetention };
