import pino from 'pino';
import { createClient } from 'redis';
import { loadEnv } from './config/env.js';
import { createDatabase } from './db/database.js';
import { migrate } from './db/migrations.js';
import { createApplication, createHttpServer } from './http/app.js';
import { RealtimeHub, type RedisBridge } from './realtime/hub.js';
import { seedDatabase } from './services/seed-data.js';

const env = loadEnv();
const logger = pino({ level: env.LOG_LEVEL, redact: ['password', 'temporaryPassword', 'authorization', 'cookie'] });
const db = await createDatabase(env);
await migrate(db);
await seedDatabase(db, false);

let redis: RedisBridge | null = null;
try {
  const client = createClient({
    url: env.REDIS_URL,
    socket: {
      connectTimeout: 2_000,
      reconnectStrategy: env.REDIS_REQUIRED ? (retries) => Math.min(3_000, 100 * 2 ** Math.min(retries, 5)) : false
    }
  });
  client.on('error', (error) => logger.warn({ err: error }, 'redis connection issue'));
  await client.connect();
  redis = client as unknown as RedisBridge;
} catch (error) {
  if (env.REDIS_REQUIRED) throw error;
  logger.warn({ err: error }, 'Redis unavailable; development fallbacks are active');
}

const realtime = new RealtimeHub(db, env);
if (redis) await realtime.useRedis(redis);
const app = createApplication({ db, env, realtime, redis, logger });
const server = createHttpServer(app, realtime);
server.listen(env.PORT, () => logger.info({ port: env.PORT, url: env.APP_URL }, 'Mandegar delivery system started'));

async function shutdown(signal: string) {
  logger.info({ signal }, 'graceful shutdown started');
  server.close();
  await realtime.close();
  if (redis?.isOpen) await redis.quit();
  await db.close();
  process.exit(0);
}
process.on('SIGINT', () => void shutdown('SIGINT'));
process.on('SIGTERM', () => void shutdown('SIGTERM'));
