import { ConvexError, v } from 'convex/values';

import type { Doc, Id } from './_generated/dataModel';
import type { MutationCtx } from './_generated/server';
import {
  internalMutation,
  internalQuery,
  mutation,
  query,
} from './_generated/server';
import { getRequiredUserId } from './model';

const reasoningEffort = v.union(
  v.literal('none'),
  v.literal('minimal'),
  v.literal('low'),
  v.literal('medium'),
  v.literal('high'),
  v.literal('xhigh'),
);

export const getMine = query({
  args: {},
  handler: async (ctx) => {
    const userId = await getRequiredUserId(ctx);
    const settings = await ctx.db
      .query('userAiSettings')
      .withIndex('by_user_provider', (q) =>
        q.eq('userId', userId).eq('provider', 'openai'),
      )
      .first();
    if (!settings) {
      return {
        configured: false,
        apiKeyPreview: undefined,
        model: 'gpt-5.5',
        reasoningEffort: 'medium' as const,
        updatedAt: undefined,
      };
    }
    return {
      configured: Boolean(settings.encryptedApiKey),
      apiKeyPreview: settings.apiKeyPreview,
      model: settings.model,
      reasoningEffort: settings.reasoningEffort,
      updatedAt: settings.updatedAt,
    };
  },
});

export const getForUserInternal = internalQuery({
  args: { userId: v.id('users') },
  handler: async (ctx, { userId }) => {
    return await ctx.db
      .query('userAiSettings')
      .withIndex('by_user_provider', (q) =>
        q.eq('userId', userId).eq('provider', 'openai'),
      )
      .first();
  },
});

const upsert = async (
  ctx: MutationCtx,
  userId: Id<'users'>,
  patch: Partial<Doc<'userAiSettings'>>,
) => {
  const now = Date.now();
  const existing = await ctx.db
    .query('userAiSettings')
    .withIndex('by_user_provider', (q) =>
      q.eq('userId', userId).eq('provider', 'openai'),
    )
    .first();
  if (existing) {
    await ctx.db.patch(existing._id, { ...patch, updatedAt: now });
    return existing._id;
  }
  return await ctx.db.insert('userAiSettings', {
    userId,
    provider: 'openai',
    model: patch.model ?? 'gpt-5.5',
    reasoningEffort: patch.reasoningEffort ?? 'medium',
    encryptedApiKey: patch.encryptedApiKey,
    apiKeyPreview: patch.apiKeyPreview,
    createdAt: now,
    updatedAt: now,
  });
};

export const upsertEncryptedInternal = internalMutation({
  args: {
    userId: v.id('users'),
    encryptedApiKey: v.string(),
    apiKeyPreview: v.string(),
    model: v.string(),
    reasoningEffort,
  },
  handler: async (ctx, args) => {
    return await upsert(ctx, args.userId, {
      encryptedApiKey: args.encryptedApiKey,
      apiKeyPreview: args.apiKeyPreview,
      model: args.model,
      reasoningEffort: args.reasoningEffort,
    });
  },
});

export const updatePreferences = mutation({
  args: {
    model: v.string(),
    reasoningEffort,
  },
  handler: async (ctx, args) => {
    const userId = await getRequiredUserId(ctx);
    return await upsert(ctx, userId, {
      model: args.model.trim() || 'gpt-5.5',
      reasoningEffort: args.reasoningEffort,
    });
  },
});

export const removeOpenAiKey = mutation({
  args: {},
  handler: async (ctx) => {
    const userId = await getRequiredUserId(ctx);
    const settings = await ctx.db
      .query('userAiSettings')
      .withIndex('by_user_provider', (q) =>
        q.eq('userId', userId).eq('provider', 'openai'),
      )
      .first();
    if (!settings) throw new ConvexError('OpenAI settings not found.');
    await ctx.db.patch(settings._id, {
      encryptedApiKey: undefined,
      apiKeyPreview: undefined,
      updatedAt: Date.now(),
    });
    return { success: true };
  },
});
