// src/services/user.ts
// Copyright (C) 2026 DTP Technologies, LLC
// All Rights Reserved

import crypto from "crypto";
import { Types } from "mongoose";

import { DtpService } from "../lib/service.js";
import User, { IUser } from "../models/user.js";
import env from "../config/env.js";

export class UserService extends DtpService {
  get name(): string {
    return "UserService";
  }
  get slug(): string {
    return "user";
  }

  constructor() {
    super();
  }

  async start(): Promise<void> {
    this.log.info("service started");
  }

  async stop(): Promise<void> {
    this.log.info("service stopped");
  }

  /**
   * Create a new user account
   */
  async create(
    username: string,
    password: string,
    displayName: string,
    isAdmin: boolean = false,
  ): Promise<IUser> {
    // Validate input
    if (!username || !password || !displayName) {
      throw new Error("Username, password, and display name are required");
    }

    if (username.length < 3 || username.length > 12) {
      throw new Error("Username must be between 3 and 12 characters");
    }

    if (password.length < 8) {
      throw new Error("Password must be at least 8 characters");
    }

    if (displayName.length < 3 || displayName.length > 30) {
      throw new Error("Display name must be between 3 and 30 characters");
    }

    // Check if user already exists
    const existingUser = await User.findOne({
      username_lc: username.toLowerCase(),
    });

    if (existingUser) {
      throw new Error("Username already taken");
    }

    // Hash password with salt
    const passwordSalt = env.user.passwordSalt;
    const passwordHash = crypto
      .pbkdf2Sync(password, passwordSalt, 100000, 64, "sha512")
      .toString("hex");

    // Create user
    const user = new User();
    user.username = username;
    user.username_lc = username.toLowerCase();
    user.password = passwordHash;
    user.passwordSalt = passwordSalt;
    user.displayName = displayName;
    user.flags = {
      isAdmin,
      isTest: false,
      isBanned: false,
    };
    user.connections = {
      gab: {
        social: { apiToken: "" },
        ai: { apiToken: "" },
      },
      ai: {
        providerIds: [],
        agentProviderId: null,
        agentModel: "",
        vectorProviderId: null,
        vectorModel: "",
        utilityProviderId: null,
        utilityModel: "",
      },
    };

    await user.save();
    this.log.info("User created", {
      userId: user._id,
      username: user.username,
    });

    return user;
  }

  /**
   * Get user by ID
   */
  async getUserById(_id: Types.ObjectId): Promise<IUser | null> {
    const user = await User.findById(_id);
    return user;
  }

  /**
   * Get user by username (case-insensitive)
   */
  async getUserByUsername(username: string): Promise<IUser | null> {
    const user = await User.findOne({
      username_lc: username.toLowerCase(),
    });
    return user;
  }

  /**
   * Get user by ID with sensitive fields (for auth purposes)
   */
  async getUserByIdWithCredentials(_id: Types.ObjectId): Promise<IUser | null> {
    const user = await User.findById(_id).select("+password +passwordSalt");
    return user;
  }

  /**
   * Get user by username with sensitive fields (for auth purposes)
   */
  async getUserByUsernameWithCredentials(
    username: string,
  ): Promise<IUser | null> {
    const user = await User.findOne({
      username_lc: username.toLowerCase(),
    }).select("+password +passwordSalt");
    return user;
  }

  /**
   * Verify user password
   */
  async verifyPassword(user: IUser, password: string): Promise<boolean> {
    if (!user.password || !user.passwordSalt) {
      return false;
    }

    const passwordHash = crypto
      .pbkdf2Sync(password, user.passwordSalt, 100000, 64, "sha512")
      .toString("hex");

    return passwordHash === user.password;
  }

  /**
   * Check if user is banned
   */
  isUserBanned(user: IUser): boolean {
    return user.flags.isBanned;
  }

  /**
   * Get public user data (safe to expose to client)
   */
  getPublicUserData(user: IUser): {
    _id: string;
    username: string;
    displayName: string;
    flags: IUser["flags"];
  } {
    return {
      _id: user._id.toString(),
      username: user.username,
      displayName: user.displayName,
      flags: user.flags,
    };
  }
}

export default new UserService();
