'use strict';

// import required so Node type-strips this .cts (it has no other import).
import type { Db } from '../types/db';

const MAX_RECENT_ERRORS = 10;

// Keys written to the settings table for cross-restart persistence
const DB_KEY = {
  workerLastRun: '_worker_last_run_at',
  workerNextRun: '_worker_next_run_at',
  workerError: '_worker_last_error',
  workerStarted: '_worker_started_at',
};

interface WorkerState {
  enabled: boolean;
  running: boolean;
  started_at: string | null;
  last_run_at: string | null;
  next_run_at: string | null;
  last_error: string | null;
}
interface NotificationsState {
  last_test_at: string | null;
  last_error: string | null;
}
interface RuntimeError {
  timestamp: string;
  source: string;
  message: string;
}

const state: {
  worker: WorkerState;
  notifications: NotificationsState;
  recentErrors: RuntimeError[];
} = {
  worker: {
    enabled: false,
    running: false,
    started_at: null,
    last_run_at: null,
    next_run_at: null,
    last_error: null,
  },
  notifications: {
    last_test_at: null,
    last_error: null,
  },
  recentErrors: [],
};

// Seed from DB on first load so status survives container restarts.
// Wrapped in try/catch — DB may not be ready at require-time in tests.
function seedFromDb(): void {
  try {
    const { getSetting } = require('../db/database.cts');
    state.worker.last_run_at = getSetting(DB_KEY.workerLastRun) || null;
    state.worker.next_run_at = getSetting(DB_KEY.workerNextRun) || null;
    state.worker.last_error = getSetting(DB_KEY.workerError) || null;
    state.worker.started_at = getSetting(DB_KEY.workerStarted) || null;
    if (state.worker.last_run_at) state.worker.enabled = true;
  } catch {
    /* DB not ready — will be populated when workers run */
  }
}
seedFromDb();

function dbSet(key: string, value: unknown): void {
  try {
    const { setSetting } = require('../db/database.cts');
    setSetting(key, value == null ? '' : String(value));
  } catch {
    /* non-fatal */
  }
}

function toMessage(error: unknown): string | null {
  if (!error) return null;
  if (typeof error === 'string') return error;
  return (error as any).message || String(error);
}

function recordError(source: string, error: unknown): void {
  const message = toMessage(error);
  if (!message) return;
  state.recentErrors.unshift({ timestamp: new Date().toISOString(), source, message });
  state.recentErrors = state.recentErrors.slice(0, MAX_RECENT_ERRORS);
}

function markWorkerStarted(nextRunAt: string | null = null): void {
  const now = new Date().toISOString();
  state.worker.enabled = true;
  state.worker.running = true;
  state.worker.started_at = state.worker.started_at || now;
  state.worker.next_run_at = nextRunAt;
  dbSet(DB_KEY.workerStarted, state.worker.started_at);
  if (nextRunAt) dbSet(DB_KEY.workerNextRun, nextRunAt);
}

function markWorkerSuccess(nextRunAt: string | null = null): void {
  const now = new Date().toISOString();
  state.worker.running = false;
  state.worker.last_run_at = now;
  state.worker.last_error = null;
  if (nextRunAt !== undefined) state.worker.next_run_at = nextRunAt;
  dbSet(DB_KEY.workerLastRun, now);
  dbSet(DB_KEY.workerError, '');
  if (nextRunAt) dbSet(DB_KEY.workerNextRun, nextRunAt);
}

function markWorkerError(error: unknown, nextRunAt: string | null = null): void {
  const now = new Date().toISOString();
  state.worker.running = false;
  state.worker.last_run_at = now;
  state.worker.last_error = toMessage(error);
  if (nextRunAt !== undefined) state.worker.next_run_at = nextRunAt;
  dbSet(DB_KEY.workerLastRun, now);
  dbSet(DB_KEY.workerError, state.worker.last_error || '');
  if (nextRunAt) dbSet(DB_KEY.workerNextRun, nextRunAt);
  recordError('Daily Worker', error);
}

function markNotificationTestSuccess(): void {
  state.notifications.last_test_at = new Date().toISOString();
  state.notifications.last_error = null;
}

function markNotificationError(error: unknown): void {
  state.notifications.last_error = toMessage(error);
  recordError('Notifications', error);
}

function markNotificationSuccess(): void {
  state.notifications.last_error = null;
}

function getStatusRuntime() {
  return {
    worker: { ...state.worker },
    notifications: { ...state.notifications },
    recentErrors: [...state.recentErrors],
  };
}

module.exports = {
  getStatusRuntime,
  markNotificationError,
  markNotificationSuccess,
  markNotificationTestSuccess,
  markWorkerError,
  markWorkerStarted,
  markWorkerSuccess,
  recordError,
};
