import bcrypt from "bcrypt";
import jwt, { type SignOptions } from "jsonwebtoken";
import type { Context } from "koa";
import appConfig from "../config/app";
import dbConfig from "../config/database";
import jwtConfig from "../config/jwt";
import type { User } from "../models";
import DatabaseService from "../services/database";

const db = DatabaseService.getInstance();

export default {
  // User registration
  async register(ctx: Context) {
    const { username, password, email } = ctx.request.body as {
      username: string;
      password: string;
      email?: string;
    };

    // Validate input
    if (!username || !password) {
      ctx.status = 400;
      ctx.body = {
        success: false,
        message: "Username and password are required",
      };
      return;
    }

    try {
      const usersCollection = db.getCollection<User>(
        dbConfig.collections.users,
      );

      // Check if user already exists
      const existingUser = await usersCollection.findOne({ username });
      if (existingUser) {
        ctx.status = 409;
        ctx.body = { success: false, message: "Username already exists" };
        return;
      }

      // Hash password before saving
      const salt = await bcrypt.genSalt(10);
      const hashedPassword = await bcrypt.hash(password, salt);

      // Create new user
      const now = new Date();
      const newUser: User = {
        username,
        password: hashedPassword,
        email,
        createdAt: now,
        updatedAt: now,
      };

      // Save user to database
      const result = await usersCollection.insertOne(newUser);

      ctx.status = 201;
      ctx.body = {
        success: true,
        message: "User registered successfully",
        userId: result.insertedId,
      };
    } catch (error) {
      ctx.status = 500;
      ctx.body = {
        success: false,
        message: "Error registering user",
        error: (error as Error).message,
      };
    }
  },

  // Admin registration
  async registerAdmin(ctx: Context) {
    const { username, password, email, adminKey } = ctx.request.body as {
      username: string;
      password: string;
      email?: string;
      adminKey: string;
    };

    // Validate input
    if (!username || !password) {
      ctx.status = 400;
      ctx.body = {
        success: false,
        message: "Username and password are required",
      };
      return;
    }

    // Validate admin key
    const validAdminKey = appConfig.adminKey;
    if (adminKey !== validAdminKey) {
      ctx.status = 403;
      ctx.body = { success: false, message: "Invalid admin key" };
      return;
    }

    try {
      const usersCollection = db.getCollection<User>(
        dbConfig.collections.users,
      );

      // Check if user already exists
      const existingUser = await usersCollection.findOne({ username });
      if (existingUser) {
        ctx.status = 409;
        ctx.body = { success: false, message: "Username already exists" };
        return;
      }

      // Hash password before saving
      const salt = await bcrypt.genSalt(10);
      const hashedPassword = await bcrypt.hash(password, salt);

      // Create new admin user
      const now = new Date();
      const newUser: User = {
        username,
        password: hashedPassword,
        email,
        role: "admin", // Add admin role
        createdAt: now,
        updatedAt: now,
      };

      // Save user to database
      const result = await usersCollection.insertOne(newUser);

      ctx.status = 201;
      ctx.body = {
        success: true,
        message: "Admin registered successfully",
        userId: result.insertedId,
      };
    } catch (error) {
      ctx.status = 500;
      ctx.body = {
        success: false,
        message: "Error registering admin",
        error: (error as Error).message,
      };
    }
  },

  // User login
  async login(ctx: Context) {
    const { username, password } = ctx.request.body as {
      username: string;
      password: string;
    };

    // Validate input
    if (!username || !password) {
      ctx.status = 400;
      ctx.body = {
        success: false,
        message: "Username and password are required",
      };
      return;
    }

    try {
      const usersCollection = db.getCollection<User>(
        dbConfig.collections.users,
      );

      // Check if user exists
      const user = await usersCollection.findOne({ username });
      if (!user) {
        ctx.status = 401;
        ctx.body = { success: false, message: "Invalid credentials" };
        return;
      }

      // Verify password
      const isPasswordValid = await bcrypt.compare(password, user.password);
      if (!isPasswordValid) {
        ctx.status = 401;
        ctx.body = { success: false, message: "Invalid credentials" };
        return;
      }

      // Generate JWT token
      const token = jwt.sign(
        {
          id: user._id?.toString(),
          username: user.username,
        },
        jwtConfig.secret,
        { expiresIn: jwtConfig.expiresIn } as SignOptions,
      );

      ctx.body = {
        success: true,
        message: "Login successful",
        userId: user._id,
        username: user.username,
        token,
      };
    } catch (error) {
      ctx.status = 500;
      ctx.body = {
        success: false,
        message: "Error during login",
        error: (error as Error).message,
      };
    }
  },
};
