const crypto = require("crypto");
const jwt = require("jsonwebtoken");
const { jwtSecret, jwtExpiresIn, jwtRefreshExpiresIn } = require("../config/env");
const { normalizeUsername } = require("../utils/helpers");

function parseDemoUsers(rawValue) {
  const fallbackUsers = [
    { id: "u-alice", username: "alice", password: "alice123", role: "user" },
    { id: "u-bob", username: "bob", password: "bob123", role: "user" }
  ];

  if (!rawValue) {
    return fallbackUsers;
  }

  try {
    const parsed = JSON.parse(rawValue);
    if (!Array.isArray(parsed)) {
      return fallbackUsers;
    }

    const normalized = parsed
      .filter((entry) => entry && entry.id && entry.username && entry.password)
      .map((entry) => ({
        id: String(entry.id),
        username: String(entry.username),
        password: String(entry.password),
        role: String(entry.role || "user")
      }));

    return normalized.length ? normalized : fallbackUsers;
  } catch {
    return fallbackUsers;
  }
}

const users = parseDemoUsers(process.env.DEMO_USERS_JSON);

function login(usernameInput, password) {
  const username = normalizeUsername(usernameInput);
  const user = users.find((entry) => entry.username === username && entry.password === password);
  if (!user) {
    return null;
  }
  return buildAuthResponse(user);
}

function register(usernameInput, password) {
  const username = normalizeUsername(usernameInput);

  if (!username || username.length < 3) {
    return { error: "username must be at least 3 characters", status: 400 };
  }
  if (!/^[a-zA-Z0-9_.-]+$/.test(username)) {
    return { error: "username may only contain letters, numbers, ., _, -", status: 400 };
  }
  if (password.length < 6) {
    return { error: "password must be at least 6 characters", status: 400 };
  }

  const existing = users.find((entry) => entry.username === username);
  if (existing) {
    return { error: "username already exists", status: 409 };
  }

  const user = {
    id: `u-${username}-${crypto.randomBytes(4).toString("hex")}`,
    username,
    password,
    role: "user"
  };
  users.push(user);
  return { data: buildAuthResponse(user), status: 201 };
}

function verifyToken(token) {
  const payload = jwt.verify(token, jwtSecret);
  if (payload.tokenType !== "access") {
    throw new Error("invalid token type");
  }
  return {
    id: String(payload.sub),
    username: String(payload.username || ""),
    role: String(payload.role || "user")
  };
}

function signAccessToken(user) {
  return jwt.sign({ sub: user.id, username: user.username, role: user.role, tokenType: "access" }, jwtSecret, {
    expiresIn: jwtExpiresIn
  });
}

function signRefreshToken(user) {
  return jwt.sign({ sub: user.id, tokenType: "refresh" }, jwtSecret, {
    expiresIn: jwtRefreshExpiresIn
  });
}

function buildAuthResponse(user) {
  const token = signAccessToken(user);
  const refreshToken = signRefreshToken(user);

  return {
    token,
    refreshToken,
    user: { id: user.id, username: user.username, role: user.role }
  };
}

function refreshSession(refreshTokenInput) {
  if (typeof refreshTokenInput !== "string" || !refreshTokenInput) {
    return null;
  }

  const payload = jwt.verify(refreshTokenInput, jwtSecret);
  if (payload.tokenType !== "refresh") {
    return null;
  }

  const user = users.find((entry) => entry.id === String(payload.sub));
  if (!user) {
    return null;
  }

  return buildAuthResponse(user);
}

module.exports = {
  login,
  register,
  verifyToken,
  refreshSession
};
