import { query, mutation, internalMutation } from "./_generated/server";
import { v } from "convex/values";
import { getRolesForUser } from "./roles";

export const get = query({
  args: {},
  returns: v.any(),
  handler: async (ctx) => {
    const settings = await ctx.db.query("serverSettings").first();
    if (!settings) return null;
    let iconUrl = null;
    if (settings.iconStorageId) {
      iconUrl = await ctx.storage.getUrl(settings.iconStorageId);
    }
    return { ...settings, iconUrl };
  },
});

export const update = mutation({
  args: {
    userId: v.id("userProfiles"),
    afkChannelId: v.optional(v.id("channels")),
    afkTimeout: v.number(),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    // Permission check
    const roles = await getRolesForUser(ctx, args.userId);
    const canManage = roles.some(
      (role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
    );
    if (!canManage) {
      throw new Error("You don't have permission to manage server settings");
    }

    // Validate timeout range
    if (args.afkTimeout < 60 || args.afkTimeout > 3600) {
      throw new Error("AFK timeout must be between 60 and 3600 seconds");
    }

    // Validate AFK channel is a voice channel if provided
    if (args.afkChannelId) {
      const channel = await ctx.db.get(args.afkChannelId);
      if (!channel) throw new Error("AFK channel not found");
      if (channel.type !== "voice") throw new Error("AFK channel must be a voice channel");
    }

    const existing = await ctx.db.query("serverSettings").first();
    if (existing) {
      await ctx.db.patch(existing._id, {
        afkChannelId: args.afkChannelId,
        afkTimeout: args.afkTimeout,
      });
    } else {
      await ctx.db.insert("serverSettings", {
        afkChannelId: args.afkChannelId,
        afkTimeout: args.afkTimeout,
      });
    }

    return null;
  },
});

export const updateName = mutation({
  args: {
    userId: v.id("userProfiles"),
    serverName: v.string(),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    // Permission check
    const roles = await getRolesForUser(ctx, args.userId);
    const canManage = roles.some(
      (role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
    );
    if (!canManage) {
      throw new Error("You don't have permission to manage server settings");
    }

    // Validate name
    const name = args.serverName.trim();
    if (name.length === 0 || name.length > 100) {
      throw new Error("Server name must be between 1 and 100 characters");
    }

    const existing = await ctx.db.query("serverSettings").first();
    if (existing) {
      await ctx.db.patch(existing._id, { serverName: name });
    } else {
      await ctx.db.insert("serverSettings", {
        serverName: name,
        afkTimeout: 300,
      });
    }

    return null;
  },
});

export const updateIcon = mutation({
  args: {
    userId: v.id("userProfiles"),
    iconStorageId: v.optional(v.id("_storage")),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    // Permission check
    const roles = await getRolesForUser(ctx, args.userId);
    const canManage = roles.some(
      (role) => (role.permissions as Record<string, boolean>)?.["manage_channels"]
    );
    if (!canManage) {
      throw new Error("You don't have permission to manage server settings");
    }

    const existing = await ctx.db.query("serverSettings").first();
    if (existing) {
      await ctx.db.patch(existing._id, {
        iconStorageId: args.iconStorageId,
      });
    } else {
      await ctx.db.insert("serverSettings", {
        iconStorageId: args.iconStorageId,
        afkTimeout: 300,
      });
    }

    return null;
  },
});

export const clearAfkChannel = internalMutation({
  args: { channelId: v.id("channels") },
  returns: v.null(),
  handler: async (ctx, args) => {
    const settings = await ctx.db.query("serverSettings").first();
    if (settings && settings.afkChannelId === args.channelId) {
      await ctx.db.patch(settings._id, { afkChannelId: undefined });
    }
    return null;
  },
});
