const bcrypt =
  require("bcryptjs");

require("dotenv").config();

const {
  pool
} = require("../config/db");

const {
  writeAdminAuditLog
} = require(
  "../services/adminAuditService"
);

const validatePassword = (
  password
) => {
  if (
    typeof password !==
      "string" ||
    password.length < 12
  ) {
    throw new Error(
      "Initial administrator password must contain at least 12 characters."
    );
  }

  if (
    !/[a-z]/.test(password) ||
    !/[A-Z]/.test(password) ||
    !/\d/.test(password) ||
    !/[^A-Za-z0-9]/.test(
      password
    )
  ) {
    throw new Error(
      "Initial administrator password must contain uppercase, lowercase, number and special characters."
    );
  }
};

const createInitialAdmin =
  async () => {
    const fullName =
      String(
        process.env
          .INITIAL_ADMIN_FULL_NAME ||
        ""
      ).trim();

    const username =
      String(
        process.env
          .INITIAL_ADMIN_USERNAME ||
        ""
      )
        .trim()
        .toLowerCase();

    const email =
      String(
        process.env
          .INITIAL_ADMIN_EMAIL ||
        ""
      )
        .trim()
        .toLowerCase();

    const password =
      String(
        process.env
          .INITIAL_ADMIN_PASSWORD ||
        ""
      );

    if (
      !fullName ||
      !username ||
      !email ||
      !password
    ) {
      throw new Error(
        "INITIAL_ADMIN_FULL_NAME, INITIAL_ADMIN_USERNAME, INITIAL_ADMIN_EMAIL and INITIAL_ADMIN_PASSWORD are required."
      );
    }

    validatePassword(
      password
    );

    const [existingRows] =
      await pool.query(
        `
          SELECT
            id,
            username,
            email
          FROM admin_users
          WHERE
            LOWER(username) = ?
            OR LOWER(email) = ?
          LIMIT 1
        `,
        [
          username,
          email
        ]
      );

    if (
      existingRows.length > 0
    ) {
      throw new Error(
        "An administrator already exists with this username or email address."
      );
    }

    const passwordHash =
      await bcrypt.hash(
        password,
        12
      );

    const [insertResult] =
      await pool.query(
        `
          INSERT INTO admin_users (
            full_name,
            username,
            email,
            password_hash,
            role,
            status,
            password_changed_at
          )
          VALUES (
            ?,
            ?,
            ?,
            ?,
            'super_admin',
            'active',
            NOW()
          )
        `,
        [
          fullName,
          username,
          email,
          passwordHash
        ]
      );

    await writeAdminAuditLog({
      adminUserId:
        insertResult.insertId,

      action:
        "INITIAL_SUPER_ADMIN_CREATED",

      entityType:
        "admin_user",

      entityId:
        insertResult.insertId,

      description:
        "The initial Super Administrator account was created."
    });

    console.log(
      "========================================"
    );

    console.log(
      "Initial Super Admin created successfully."
    );

    console.log(
      `Name: ${fullName}`
    );

    console.log(
      `Username: ${username}`
    );

    console.log(
      `Email: ${email}`
    );

    console.log(
      "Role: super_admin"
    );

    console.log(
      "========================================"
    );
  };

createInitialAdmin()
  .catch((error) => {
    console.error(
      "Unable to create initial administrator:",
      error.message
    );

    process.exitCode = 1;
  })
  .finally(async () => {
    await pool.end();
  });