/**
 * JSONL-based Feedback Store
 *
 * Append-only daily JSONL files for raw feedback events.
 * - data/feedback/raw/{YYYY-MM-DD}.jsonl — immutable daily logs
 * - Each line is a complete JSON object (one EnrichedFeedbackEvent)
 * - Files are naturally partitioned by day for easy archival
 */

import * as fs from "node:fs";
import * as path from "node:path";
import type { EnrichedFeedbackEvent } from "../types.js";

// ═══════════════════════════════════════════════════════════════
// FILE PATHS
// ═══════════════════════════════════════════════════════════════

function getRawDir(dataDir: string): string {
  return path.join(dataDir, "feedback", "raw");
}

function getDailyFilePath(dataDir: string, date: Date): string {
  const dateStr = formatDate(date);
  return path.join(getRawDir(dataDir), `${dateStr}.jsonl`);
}

function formatDate(date: Date): string {
  return date.toISOString().split("T")[0]!;
}

// ═══════════════════════════════════════════════════════════════
// APPEND
// ═══════════════════════════════════════════════════════════════

/**
 * Append a feedback event to the daily JSONL file.
 * Creates the file and directories if they don't exist.
 *
 * @returns The file path where the event was stored
 */
export async function appendFeedback(
  event: EnrichedFeedbackEvent,
  dataDir: string
): Promise<string> {
  const eventDate = new Date(event.timestamp);
  const filePath = getDailyFilePath(dataDir, eventDate);

  // Ensure directory exists
  const dir = path.dirname(filePath);
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }

  // Append as a single JSONL line
  const line = JSON.stringify(event) + "\n";
  fs.appendFileSync(filePath, line, "utf-8");

  return filePath;
}

// ═══════════════════════════════════════════════════════════════
// LOAD
// ═══════════════════════════════════════════════════════════════

/**
 * Load feedback events from the past N days.
 */
export async function loadFeedbackEvents(
  dataDir: string,
  days: number = 30
): Promise<EnrichedFeedbackEvent[]> {
  const rawDir = getRawDir(dataDir);
  const events: EnrichedFeedbackEvent[] = [];

  if (!fs.existsSync(rawDir)) {
    return events;
  }

  const now = new Date();
  const cutoff = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);

  // Read all JSONL files in the raw directory
  const files = fs.readdirSync(rawDir).filter((f) => f.endsWith(".jsonl")).sort();

  for (const file of files) {
    // Parse date from filename
    const dateStr = file.replace(".jsonl", "");
    const fileDate = new Date(dateStr + "T00:00:00Z");

    // Skip files older than cutoff
    if (fileDate < cutoff) continue;

    const filePath = path.join(rawDir, file);
    const content = fs.readFileSync(filePath, "utf-8");

    for (const line of content.split("\n")) {
      if (line.trim().length === 0) continue;
      try {
        const event = JSON.parse(line) as EnrichedFeedbackEvent;
        events.push(event);
      } catch {
        // Skip malformed lines — log warning in production
        console.warn(`Skipping malformed line in ${file}`);
      }
    }
  }

  return events;
}

/**
 * Load feedback events for a specific date.
 */
export async function loadFeedbackForDate(
  dataDir: string,
  date: Date
): Promise<EnrichedFeedbackEvent[]> {
  const filePath = getDailyFilePath(dataDir, date);

  if (!fs.existsSync(filePath)) {
    return [];
  }

  const content = fs.readFileSync(filePath, "utf-8");
  const events: EnrichedFeedbackEvent[] = [];

  for (const line of content.split("\n")) {
    if (line.trim().length === 0) continue;
    try {
      events.push(JSON.parse(line) as EnrichedFeedbackEvent);
    } catch {
      // Skip malformed lines
    }
  }

  return events;
}

/**
 * Count total stored events across all files.
 */
export async function countStoredEvents(dataDir: string): Promise<number> {
  const rawDir = getRawDir(dataDir);

  if (!fs.existsSync(rawDir)) return 0;

  let count = 0;
  const files = fs.readdirSync(rawDir).filter((f) => f.endsWith(".jsonl"));

  for (const file of files) {
    const content = fs.readFileSync(path.join(rawDir, file), "utf-8");
    count += content.split("\n").filter((l) => l.trim().length > 0).length;
  }

  return count;
}

/**
 * Get list of available date files.
 */
export function getAvailableDates(dataDir: string): string[] {
  const rawDir = getRawDir(dataDir);

  if (!fs.existsSync(rawDir)) return [];

  return fs
    .readdirSync(rawDir)
    .filter((f) => f.endsWith(".jsonl"))
    .map((f) => f.replace(".jsonl", ""))
    .sort();
}
