import { v } from 'convex/values';

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

const defaultSettings = {
  autoRefreshEnabled: true,
  autoReviewEnabled: true,
  autoSyncEnabled: false,
  requireAiLowRiskForSync: true,
  requireCleanCompareForSync: true,
  ignoredFilePatterns: [] as string[],
  importantFilePatterns: [] as string[],
};

export const getForSpoon = query({
  args: { spoonId: v.id('spoons') },
  handler: async (ctx, { spoonId }) => {
    const ownerId = await getRequiredUserId(ctx);
    await getOwnedSpoon(ctx, spoonId, ownerId);
    return (
      (await ctx.db
        .query('spoonSettings')
        .withIndex('by_spoon', (q) => q.eq('spoonId', spoonId))
        .first()) ?? { spoonId, ownerId, ...defaultSettings }
    );
  },
});

export const ensureForSpoon = internalMutation({
  args: { spoonId: v.id('spoons'), ownerId: v.id('users') },
  handler: async (ctx, { spoonId, ownerId }) => {
    const existing = await ctx.db
      .query('spoonSettings')
      .withIndex('by_spoon', (q) => q.eq('spoonId', spoonId))
      .first();
    if (existing) return existing._id;
    const now = Date.now();
    return await ctx.db.insert('spoonSettings', {
      spoonId,
      ownerId,
      ...defaultSettings,
      createdAt: now,
      updatedAt: now,
    });
  },
});

export const getInternal = internalQuery({
  args: { spoonId: v.id('spoons'), ownerId: v.id('users') },
  handler: async (ctx, { spoonId, ownerId }) => {
    const settings = await ctx.db
      .query('spoonSettings')
      .withIndex('by_spoon', (q) => q.eq('spoonId', spoonId))
      .first();
    if (settings && settings.ownerId !== ownerId) {
      throw new Error('Spoon settings ownership mismatch.');
    }
    return settings;
  },
});

export const listRefreshDue = internalQuery({
  args: { limit: v.number() },
  handler: async (ctx, { limit }) => {
    const now = Date.now();
    const settings = await ctx.db.query('spoonSettings').collect();
    const due = [];
    for (const item of settings) {
      if (!item.autoRefreshEnabled) continue;
      const spoon = await ctx.db.get(item.spoonId);
      if (
        !spoon ||
        spoon.status === 'archived' ||
        spoon.provider !== 'github'
      ) {
        continue;
      }
      if (spoon.syncCadence === 'manual') continue;
      const cadenceMs =
        spoon.syncCadence === 'weekly'
          ? 7 * 24 * 60 * 60 * 1000
          : 24 * 60 * 60 * 1000;
      const last = spoon.lastGithubRefreshAt ?? spoon.lastCheckedAt ?? 0;
      if (now - last >= cadenceMs) {
        due.push({ spoonId: item.spoonId, ownerId: item.ownerId });
      }
      if (due.length >= limit) break;
    }
    return due;
  },
});

export const update = mutation({
  args: {
    spoonId: v.id('spoons'),
    autoRefreshEnabled: v.optional(v.boolean()),
    autoReviewEnabled: v.optional(v.boolean()),
    autoSyncEnabled: v.optional(v.boolean()),
    requireAiLowRiskForSync: v.optional(v.boolean()),
    requireCleanCompareForSync: v.optional(v.boolean()),
    ignoredFilePatterns: v.optional(v.array(v.string())),
    importantFilePatterns: v.optional(v.array(v.string())),
  },
  handler: async (ctx, args) => {
    const ownerId = await getRequiredUserId(ctx);
    await getOwnedSpoon(ctx, args.spoonId, ownerId);
    let settings = await ctx.db
      .query('spoonSettings')
      .withIndex('by_spoon', (q) => q.eq('spoonId', args.spoonId))
      .first();
    if (!settings) {
      const id = await ctx.db.insert('spoonSettings', {
        spoonId: args.spoonId,
        ownerId,
        ...defaultSettings,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      });
      settings = await ctx.db.get(id);
    }
    const patch: Partial<Doc<'spoonSettings'>> = { updatedAt: Date.now() };
    if (args.autoRefreshEnabled !== undefined) {
      patch.autoRefreshEnabled = args.autoRefreshEnabled;
    }
    if (args.autoReviewEnabled !== undefined) {
      patch.autoReviewEnabled = args.autoReviewEnabled;
    }
    if (args.autoSyncEnabled !== undefined) {
      patch.autoSyncEnabled = args.autoSyncEnabled;
    }
    if (args.requireAiLowRiskForSync !== undefined) {
      patch.requireAiLowRiskForSync = args.requireAiLowRiskForSync;
    }
    if (args.requireCleanCompareForSync !== undefined) {
      patch.requireCleanCompareForSync = args.requireCleanCompareForSync;
    }
    if (args.ignoredFilePatterns !== undefined) {
      patch.ignoredFilePatterns = args.ignoredFilePatterns;
    }
    if (args.importantFilePatterns !== undefined) {
      patch.importantFilePatterns = args.importantFilePatterns;
    }
    if (!settings) throw new Error('Spoon settings not found.');
    await ctx.db.patch(settings._id, patch);
    return { success: true };
  },
});
