import { ConvexError, v } from 'convex/values';
import {
  convexAuth,
  getAuthUserId,
  retrieveAccount,
  modifyAccountCredentials,
} from '@convex-dev/auth/server';
import { api } from './_generated/api';
import { type Id } from './_generated/dataModel';
import { action, mutation, query } from './_generated/server';
import Password from './CustomPassword';

export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({
  providers: [Password],
});

export const PASSWORD_MIN = 8;
export const PASSWORD_MAX = 100;
export const PASSWORD_REGEX =
  /^(?=.{8,100}$)(?!.*\s)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[\p{P}\p{S}]).*$/u;

export const getUser = query(async (ctx) => {
  const userId = await getAuthUserId(ctx);
  if (!userId) return null;
  const user = await ctx.db.get(userId);
  if (!user) throw new ConvexError('User not found.');
  const image: Id<'_storage'> | null =
    typeof user.image === 'string' && user.image.length > 0
      ? (user.image as Id<'_storage'>)
      : null;
  return {
    id: user._id,
    email: user.email ?? null,
    name: user.name ?? null,
    image,
  };
});

export const getAllUsers = query(async (ctx) => {
  const users = await ctx.db.query('users').collect();
  return users.map((u) => ({
    id: u._id,
    email: u.email ?? null,
    name: u.name ?? null,
    image: u.image ?? null,
  }));
});

export const getAllUserIds = query(async (ctx) => {
  const users = await ctx.db.query('users').collect();
  const userIds = users.map((u) => u._id);
  return userIds;
});

export const updateUserName = mutation({
  args: {
    name: v.string(),
  },
  handler: async (ctx, { name }) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new ConvexError('Not authenticated.');
    const user = await ctx.db.get(userId);
    if (!user) throw new ConvexError('User not found.');
    await ctx.db.patch(userId, { name });
    return { success: true };
  },
});

export const updateUserEmail = mutation({
  args: {
    email: v.string(),
  },
  handler: async (ctx, { email }) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new ConvexError('Not authenticated.');
    const user = await ctx.db.get(userId);
    if (!user) throw new ConvexError('User not found.');
    await ctx.db.patch(userId, { email });
    return { success: true };
  },
});

export const updateUserImage = mutation({
  args: {
    storageId: v.id('_storage'),
  },
  handler: async (ctx, { storageId }) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new ConvexError('Not authenticated.');
    const user = await ctx.db.get(userId);
    if (!user) throw new ConvexError('User not found.');
    const oldImage = user.image as Id<'_storage'> | undefined;
    await ctx.db.patch(userId, { image: storageId });
    if (oldImage && oldImage !== storageId) await ctx.storage.delete(oldImage);
    return { success: true };
  },
});

export const validatePassword = (password: string): boolean => {
  if (
    password.length < 8 ||
    password.length > 100 ||
    !/\d/.test(password) ||
    !/[a-z]/.test(password) ||
    !/[A-Z]/.test(password)
  ) {
    return false;
  }
  return true;
};

export const updateUserPassword = action({
  args: {
    currentPassword: v.string(),
    newPassword: v.string(),
  },
  handler: async (ctx, { currentPassword, newPassword }) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) throw new ConvexError('Not authenticated.');
    const user = await ctx.runQuery(api.auth.getUser);
    if (!user?.email) throw new ConvexError('User not found.');
    const verified = await retrieveAccount(ctx, {
      provider: 'password',
      account: { id: user.email, secret: currentPassword },
    });
    if (!verified) throw new ConvexError('Current password is incorrect.');

    if (!validatePassword(newPassword))
      throw new ConvexError('Invalid password.');

    await modifyAccountCredentials(ctx, {
      provider: 'password',
      account: { id: user.email, secret: newPassword },
    });

    return { success: true };
  },
});
