import { mutation, query } from "./_generated/server";
import { v } from "convex/values";
import { nowIso } from "./_utils/time";
import { generateId } from "./_utils/id";
import type { MutationCtx, QueryCtx } from "./_generated/server";

async function assertWorkspaceMember(ctx: QueryCtx | MutationCtx, userId: string, workspaceId: string) {
  const membership = await ctx.db
    .query("workspace_members")
    .withIndex("by_workspace_user", (q) => q.eq("workspace_id", workspaceId).eq("user_id", userId))
    .first();
  if (!membership) {
    throw new Error("无权访问该工作空间");
  }
  return membership;
}

// Query: 获取单个表格
export const get = query({
  args: { userId: v.string(), tableId: v.string() },
  handler: async (ctx, args) => {
    const table = await ctx.db
      .query("document_tables")
      .withIndex("by_table_id", (q) => q.eq("id", args.tableId))
      .first();
    if (!table) return null;
    if (table.workspace_id) {
      // 验证用户是否在工作区中（简化版：假设 userId 有效）
      // TODO: 添加 workspace_members 验证
    }
    return {
      id: table.id,
      workspace_id: table.workspace_id,
      document_id: table.document_id,
      grid_key: table.grid_key,
      title: table.title,
      schema: table.schema,
      view_preferences: table.view_preferences,
      snapshot: table.snapshot ?? null,
      is_archived: table.is_archived,
      last_synced_at: table.last_synced_at ?? null,
      created_by: table.created_by,
      updated_by: table.updated_by ?? null,
      created_at: table.created_at,
      updated_at: table.updated_at,
    };
  },
});

// Query: 通过 gridKey 获取表格（用于 Luckysheet get-workerbook）
export const getByGridKey = query({
  args: { gridKey: v.string() },
  handler: async (ctx, args) => {
    const table = await ctx.db
      .query("document_tables")
      .withIndex("by_grid_key", (q) => q.eq("grid_key", args.gridKey))
      .first();
    if (!table) return null;

    // 返回 Luckysheet 需要的格式
    return {
      title: table.title,
      gridKey: table.grid_key,
      lang: "zh",
    };
  },
});

// Query: 通过 gridKey 获取完整表格数据（用于 Luckysheet load）
export const getByGridKeyFull = query({
  args: { gridKey: v.string() },
  handler: async (ctx, args) => {
    const table = await ctx.db
      .query("document_tables")
      .withIndex("by_grid_key", (q) => q.eq("grid_key", args.gridKey))
      .first();
    if (!table) return null;

    // 返回完整的表格数据，包括 schema 和 snapshot
    return {
      id: table.id,
      grid_key: table.grid_key,
      title: table.title,
      schema: table.schema,
      snapshot: table.snapshot ?? null,
    };
  },
});

// Query: 列出文档的所有表格
export const listByDocument = query({
  args: { userId: v.string(), documentId: v.string() },
  handler: async (ctx, args) => {
    const tables = await ctx.db
      .query("document_tables")
      .withIndex("by_document", (q) => q.eq("document_id", args.documentId))
      .collect();

    return tables
      .filter((t) => !t.is_archived)
      .map((t) => ({
        id: t.id,
        document_id: t.document_id,
        grid_key: t.grid_key,
        title: t.title,
        schema: t.schema,
        view_preferences: t.view_preferences,
        snapshot: t.snapshot ?? null,
        is_archived: t.is_archived,
        last_synced_at: t.last_synced_at ?? null,
        created_at: t.created_at,
        updated_at: t.updated_at,
      }));
  },
});

export const listByWorkspaceForSearch = query({
  args: {
    userId: v.string(),
    workspaceId: v.string(),
    includeArchived: v.optional(v.boolean()),
    limit: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    await assertWorkspaceMember(ctx, args.userId, args.workspaceId);

    const includeArchived = Boolean(args.includeArchived);
    const limit = Math.max(1, Math.min(3000, Math.floor(args.limit ?? 3000)));

    const rows = await ctx.db
      .query("document_tables")
      .withIndex("by_workspace", (q) => q.eq("workspace_id", args.workspaceId))
      .order("desc")
      .take(limit * 2);

    return rows
      .filter((t) => (includeArchived ? true : !t.is_archived))
      .slice(0, limit)
      .map((t) => ({
        id: t.id,
        workspace_id: t.workspace_id,
        document_id: t.document_id,
        title: t.title,
        is_archived: t.is_archived,
        deleted_at: t.deleted_at ?? null,
        deleted_by: t.deleted_by ?? null,
        purged_at: t.purged_at ?? null,
        created_at: t.created_at,
        updated_at: t.updated_at,
      }));
  },
});

// Mutation: 创建表格
export const create = mutation({
  args: {
    userId: v.string(),
    workspaceId: v.string(),
    documentId: v.string(),
    title: v.optional(v.string()),
    schema: v.optional(v.any()),
    snapshot: v.optional(v.any()),
  },
  handler: async (ctx, args) => {
    const now = nowIso();
    const tableId = generateId();
    const gridKey = generateId(); // 用于 WebSocket 协同标识

    const table = {
      id: tableId,
      workspace_id: args.workspaceId,
      document_id: args.documentId,
      grid_key: gridKey,
      title: args.title ?? "未命名表格",
      schema: args.schema ?? {},
      view_preferences: {},
      snapshot: args.snapshot ?? null,
      is_archived: false,
      deleted_at: null,
      deleted_by: null,
      purged_at: null,
      last_synced_at: now,
      created_by: args.userId,
      updated_by: args.userId,
      created_at: now,
      updated_at: now,
    };

    await ctx.db.insert("document_tables", table);

    return {
      id: table.id,
      grid_key: table.grid_key,
      title: table.title,
      schema: table.schema,
      snapshot: table.snapshot,
    };
  },
});

// Mutation: 更新表格
export const update = mutation({
  args: {
    userId: v.string(),
    tableId: v.string(),
    title: v.optional(v.string()),
    schema: v.optional(v.any()),
    view_preferences: v.optional(v.any()),
    snapshot: v.optional(v.any()),
    rows: v.optional(v.any()),
  },
  handler: async (ctx, args) => {
    const table = await ctx.db
      .query("document_tables")
      .withIndex("by_table_id", (q) => q.eq("id", args.tableId))
      .first();
    if (!table) {
      throw new Error("Table not found");
    }

    const now = nowIso();
    const updates: any = {
      updated_at: now,
      updated_by: args.userId,
      last_synced_at: now,
    };

    if (args.title !== undefined) updates.title = args.title;
    if (args.schema !== undefined) updates.schema = args.schema;
    if (args.view_preferences !== undefined) updates.view_preferences = args.view_preferences;
    if (args.snapshot !== undefined) updates.snapshot = args.snapshot;

    await ctx.db.patch(table._id, updates);

    // 如果提供了 rows，更新行数据
    if (args.rows && Array.isArray(args.rows)) {
      // 先删除旧行
      const existingRows = await ctx.db
        .query("document_table_rows")
        .withIndex("by_table", (q) => q.eq("table_id", args.tableId))
        .collect();

      for (const row of existingRows) {
        await ctx.db.delete(row._id);
      }

      // 插入新行
      for (const [index, rowData] of args.rows.entries()) {
        await ctx.db.insert("document_table_rows", {
          id: generateId(),
          workspace_id: table.workspace_id,
          document_id: table.document_id,
          table_id: args.tableId,
          row_index: index,
          row_data: rowData,
          row_hash: JSON.stringify(rowData),
          is_deleted: false,
          updated_by: args.userId,
          created_at: now,
          updated_at: now,
        });
      }
    }

    return {
      id: table.id,
      title: updates.title ?? table.title,
      schema: updates.schema ?? table.schema,
      view_preferences: updates.view_preferences ?? table.view_preferences,
      snapshot: updates.snapshot ?? table.snapshot,
      updated_at: now,
    };
  },
});

// Mutation: 删除表格（软删除）
export const remove = mutation({
  args: { userId: v.string(), tableId: v.string() },
  handler: async (ctx, args) => {
    const table = await ctx.db
      .query("document_tables")
      .withIndex("by_table_id", (q) => q.eq("id", args.tableId))
      .first();
    if (!table) {
      throw new Error("Table not found");
    }

    const now = nowIso();
    await ctx.db.patch(table._id, {
      is_archived: true,
      deleted_at: now,
      deleted_by: args.userId,
      purged_at: null,
      updated_at: now,
      updated_by: args.userId,
    });

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

// Mutation: 恢复表格（从垃圾桶恢复）
export const restore = mutation({
  args: { userId: v.string(), tableId: v.string() },
  handler: async (ctx, args) => {
    const table = await ctx.db
      .query("document_tables")
      .withIndex("by_table_id", (q) => q.eq("id", args.tableId))
      .first();
    if (!table) {
      throw new Error("Table not found");
    }

    const now = nowIso();
    await ctx.db.patch(table._id, {
      is_archived: false,
      deleted_at: null,
      deleted_by: null,
      purged_at: null,
      updated_at: now,
      updated_by: args.userId,
    });

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

// Mutation: 永久删除表格
export const purge = mutation({
  args: { userId: v.string(), tableId: v.string() },
  handler: async (ctx, args) => {
    const table = await ctx.db
      .query("document_tables")
      .withIndex("by_table_id", (q) => q.eq("id", args.tableId))
      .first();
    if (!table) {
      throw new Error("Table not found");
    }

    // 删除关联的行
    const rows = await ctx.db
      .query("document_table_rows")
      .withIndex("by_table", (q) => q.eq("table_id", args.tableId))
      .collect();

    for (const row of rows) {
      await ctx.db.delete(row._id);
    }

    // 删除表格
    await ctx.db.delete(table._id);

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

export const emptyTrashByWorkspace = mutation({
  args: { userId: v.string(), workspaceId: v.string(), expiredDeletedAt: v.string() },
  handler: async (ctx, args) => {
    await assertWorkspaceMember(ctx, args.userId, args.workspaceId);

    const rows = await ctx.db
      .query("document_tables")
      .withIndex("by_workspace", (q) => q.eq("workspace_id", args.workspaceId))
      .order("desc")
      .take(5000);

    // 仅清理“已进入垃圾桶且超出宽限期”的表格
    const targets = rows.filter((t) => {
      if (!t.is_archived) return false;
      const deletedAt = (t as any).deleted_at ?? null;
      if (!deletedAt || typeof deletedAt !== "string") return false;
      return deletedAt <= args.expiredDeletedAt;
    });

    if (targets.length === 0) {
      return { ok: true, deleted: 0 };
    }

    for (const table of targets) {
      const tableId = table.id;
      const tableRows = await ctx.db
        .query("document_table_rows")
        .withIndex("by_table", (q) => q.eq("table_id", tableId))
        .collect();
      for (const r of tableRows) {
        await ctx.db.delete(r._id);
      }
      await ctx.db.delete(table._id);
    }

    return { ok: true, deleted: targets.length };
  },
});

// Query: 获取表格行数据
export const getRows = query({
  args: { tableId: v.string() },
  handler: async (ctx, args) => {
    const rows = await ctx.db
      .query("document_table_rows")
      .withIndex("by_table", (q) => q.eq("table_id", args.tableId))
      .collect();

    return rows
      .filter((r) => !r.is_deleted)
      .sort((a, b) => a.row_index - b.row_index)
      .map((r) => r.row_data);
  },
});

export const listRowsByWorkspaceForSearch = query({
  args: {
    userId: v.string(),
    workspaceId: v.string(),
    limit: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    await assertWorkspaceMember(ctx, args.userId, args.workspaceId);

    const limit = Math.max(1, Math.min(8000, Math.floor(args.limit ?? 8000)));

    const rows = await ctx.db
      .query("document_table_rows")
      .withIndex("by_workspace", (q) => q.eq("workspace_id", args.workspaceId))
      .order("desc")
      .take(limit * 2);

    return rows
      .filter((r) => !r.is_deleted)
      .slice(0, limit)
      .map((r) => ({
        id: r.id,
        workspace_id: r.workspace_id,
        document_id: r.document_id,
        table_id: r.table_id,
        row_index: r.row_index,
        row_hash: r.row_hash ?? null,
        created_at: r.created_at ?? null,
        updated_at: r.updated_at ?? null,
      }));
  },
});
