import bcrypt from "bcryptjs";

import type { AuthUser, UserRole } from "@tracker/shared";

import { env } from "../../config/env.js";
import { HttpError } from "../../lib/http-error.js";
import { signAccessToken } from "../../lib/jwt.js";
import { query, queryOne } from "../../lib/db.js";

type UserRow = {
  id: string;
  email: string;
  first_name: string;
  last_name: string;
  role: UserRole;
  can_edit_vehicle_inspection: boolean;
  can_view_stats: boolean;
  password_hash: string;
};

export const ensureUserAccessStorage = async () => {
  await query(`
    alter table users add column if not exists can_view_stats boolean not null default false;
  `);
};

export const ensureAdminUser = async () => {
  const existing = await queryOne<{ id: string }>("select id from users where email = $1", [env.ADMIN_EMAIL]);
  const passwordHash = await bcrypt.hash(env.ADMIN_PASSWORD, 10);

  if (existing) {
    await query(
      `
        update users
        set password_hash = $2, role = 'admin', updated_at = now()
        where id = $1
      `,
      [existing.id, passwordHash],
    );
    return;
  }

  await query(
    `
      insert into users (email, password_hash, role, first_name, last_name)
      values ($1, $2, 'admin', 'Admin', '')
    `,
    [env.ADMIN_EMAIL, passwordHash],
  );
};

export const login = async (email: string, password: string) => {
  const user = await queryOne<UserRow>(
    `
      select id, email, first_name, last_name, role, password_hash
      , can_edit_vehicle_inspection
      , can_view_stats
      from users
      where email = $1
    `,
    [email],
  );

  if (!user) {
    throw new HttpError(401, "Invalid credentials");
  }

  const isValid = await bcrypt.compare(password, user.password_hash);
  if (!isValid) {
    throw new HttpError(401, "Invalid credentials");
  }

  const authUser: AuthUser = {
    id: user.id,
    email: user.email,
    firstName: user.first_name,
    lastName: user.last_name,
    role: user.role,
    canEditVehicleInspection: user.can_edit_vehicle_inspection,
    canViewStats: user.can_view_stats,
  };

  return {
    token: signAccessToken(authUser),
    user: authUser,
  };
};
