import express from "express";
import mongoose from "mongoose";
import "dotenv/config";

import { createRoutes } from "./routes";
import {
  AuthController,
  ChatController,
  EventController,
  httpLogger,
} from "./controllers";
import { AuthService, ChatService, EventService } from "./services";
import {
  MongoUserRepository,
  MongoEventRepository,
  MongoChatRepository,
} from "./repositories";
import { GPTAdapter } from "./ai";
import { logger } from "./logging";
import { MongoCaldavRepository } from "./repositories/mongo/MongoCaldavRepository";
import { CaldavService } from "./services/CaldavService";
import { CaldavController } from "./controllers/CaldavController";

const app = express();
const port = process.env.PORT || 3000;
const mongoUri = process.env.MONGODB_URI || "mongodb://localhost:27017/calchat";

// Middleware
app.use(express.json());
app.use(httpLogger);

// CORS - only needed for web browser development
// Native mobile apps don't send Origin headers and aren't affected by CORS
if (process.env.NODE_ENV !== "production") {
  app.use((req, res, next) => {
    res.header("Access-Control-Allow-Origin", "*");
    res.header(
      "Access-Control-Allow-Methods",
      "GET, POST, PUT, DELETE, OPTIONS",
    );
    res.header(
      "Access-Control-Allow-Headers",
      "Content-Type, Authorization, X-User-Id",
    );
    if (req.method === "OPTIONS") {
      res.sendStatus(200);
      return;
    }
    next();
  });
}

// Initialize repositories
const userRepo = new MongoUserRepository();
const eventRepo = new MongoEventRepository();
const chatRepo = new MongoChatRepository();
const caldavRepo = new MongoCaldavRepository();

// Initialize AI provider
const aiProvider = new GPTAdapter();

// Initialize services
const authService = new AuthService(userRepo);
const eventService = new EventService(eventRepo);
const caldavService = new CaldavService(caldavRepo, eventService);
const chatService = new ChatService(chatRepo, eventService, aiProvider);

// Initialize controllers
const authController = new AuthController(authService);
const chatController = new ChatController(chatService, caldavService);
const eventController = new EventController(eventService, caldavService);
const caldavController = new CaldavController(caldavService);

// Setup routes
app.use(
  "/api",
  createRoutes({
    authController,
    chatController,
    eventController,
    caldavController,
  }),
);

// Health check
app.get("/health", (_, res) => {
  res.json({ status: "ok" });
});

// Version endpoint
app.get("/version", (_, res) => {
  res.json({
    version: process.env.VERSION || "unknown",
    commit: process.env.COMMIT || "unknown",
  });
});

// AI Test endpoint (for development only)
app.post("/api/ai/test", async (req, res) => {
  try {
    const { message } = req.body;
    if (!message) {
      res.status(400).json({ error: "message is required" });
      return;
    }
    const result = await aiProvider.processMessage(message, {
      userId: "test-user",
      conversationHistory: [],
      currentDate: new Date(),
      fetchEventsInRange: async () => [],
      searchEvents: async () => [],
      fetchEventById: async () => null,
    });
    res.json(result);
  } catch (error) {
    logger.error({ error }, "AI test error");
    res.status(500).json({ error: String(error) });
  }
});

// Start server
async function start() {
  try {
    await mongoose.connect(mongoUri);
    logger.info("Connected to MongoDB");

    app.listen(port, () => {
      logger.info({ port }, "Server started");
    });
  } catch (error) {
    logger.fatal({ error }, "Failed to start server");
    process.exit(1);
  }
}

start();

export default app;
