import Fastify from "fastify";
import helmet from "@fastify/helmet";
import cors from "@fastify/cors";
import rateLimit from "@fastify/rate-limit";
import sensible from "@fastify/sensible";
import cookie, { CookieSerializeOptions } from "@fastify/cookie";
import jwt from "@fastify/jwt";
import fastifyMultipart from "@fastify/multipart";
import fastifyStatic from "@fastify/static";
import { resolve } from "path";
import { existsSync, mkdirSync } from "fs";
import { env } from "./plugins/env.js";
import { migrationsReady } from "./db/client.js";
import { healthRoutes } from "./routes/health.js";
import { authRoutes } from "./routes/auth.js";
import { oidcRoutes } from "./routes/oidc.js";
import { medicationRoutes } from "./routes/medications.js";
import { settingsRoutes } from "./routes/settings.js";
import { plannerRoutes } from "./routes/planner.js";
import { shareRoutes } from "./routes/share.js";
import { doseRoutes } from "./routes/doses.js";
import { startReminderScheduler } from "./services/reminder-scheduler.js";
import { startIntakeReminderScheduler } from "./services/intake-reminder-scheduler.js";

// Wait for database migrations before anything else
await migrationsReady;
console.log("[DB] Migrations complete, starting server...");

// Ensure images directory exists
const imagesDir = resolve(process.cwd(), "data/images");
if (!existsSync(imagesDir)) {
  mkdirSync(imagesDir, { recursive: true });
}

const app = Fastify({
  logger: {
    level: env.LOG_LEVEL,
  },
});

const origins = env.CORS_ORIGINS.split(",").map((o) => o.trim()).filter(Boolean);

// Auth token TTLs (hardcoded - no need for user configuration)
const accessTtlMinutes = env.ACCESS_TOKEN_TTL_MINUTES;  // Access token TTL
const refreshTtlDays = env.REFRESH_TOKEN_TTL_DAYS;      // Refresh token TTL

const baseCookieOptions: CookieSerializeOptions = {
  httpOnly: true,
  sameSite: "lax",
  secure: env.NODE_ENV === "production",
  path: "/",
  maxAge: accessTtlMinutes * 60,
};

const refreshCookieOptions: CookieSerializeOptions = {
  ...baseCookieOptions,
  maxAge: refreshTtlDays * 24 * 60 * 60,
};

// Config decorator - only include secrets if auth is enabled
app.decorate("config", {
  accessSecret: env.JWT_SECRET ?? "",
  refreshSecret: env.REFRESH_SECRET ?? "",
  accessTtl: accessTtlMinutes,
  refreshTtl: refreshTtlDays,
  cookieOptions: baseCookieOptions,
  refreshCookieOptions,
});

await app.register(sensible);
await app.register(helmet);
await app.register(cors, { origin: origins, credentials: true });
await app.register(rateLimit, {
  max: 100,
  timeWindow: "1 minute",
});
await app.register(cookie, { secret: env.COOKIE_SECRET ?? "dev-cookie-secret" });

// JWT plugin - only register with valid secret if auth is enabled
if (env.AUTH_ENABLED && env.JWT_SECRET) {
  await app.register(jwt, { 
    secret: env.JWT_SECRET, 
    cookie: { cookieName: "access_token", signed: false } 
  });
} else {
  // Dummy JWT for when auth is disabled - prevents errors
  await app.register(jwt, { 
    secret: "auth-disabled-no-secret-needed", 
    cookie: { cookieName: "access_token", signed: false } 
  });
}

await app.register(fastifyMultipart, { limits: { fileSize: 10 * 1024 * 1024 } }); // 10MB limit
await app.register(fastifyStatic, {
  root: imagesDir,
  prefix: "/images/",
  decorateReply: false,
});

await app.register(healthRoutes);
await app.register(authRoutes);
await app.register(oidcRoutes);
await app.register(medicationRoutes);
await app.register(settingsRoutes);
await app.register(plannerRoutes);
await app.register(shareRoutes);
await app.register(doseRoutes);

const start = async () => {
  try {
    await app.listen({ port: env.PORT, host: "0.0.0.0" });
    app.log.info(`Server running on ${env.PORT}`);
    
    // Start the automatic reminder scheduler
    startReminderScheduler({
      info: (msg) => app.log.info(msg),
      error: (msg) => app.log.error(msg),
    });
    
    // Start the intake reminder scheduler (checks every minute)
    startIntakeReminderScheduler({
      info: (msg) => app.log.info(msg),
      error: (msg) => app.log.error(msg),
    });
  } catch (err) {
    app.log.error(err);
    process.exit(1);
  }
};

start();
