import { database, collections } from '@/database';
import { Q } from '@nozbe/watermelondb';
import { Priority, Repeat, Reminder, SubtaskData, tagsToString } from '@/types';
import { scheduleTaskReminder, cancelTaskReminder } from '@/services/notifications';
import { recordTombstonesInBatch } from '@/database/tombstones';

function mapSubtaskRow(s: any, taskId?: string): SubtaskData {
  return {
    id: s.id,
    taskId: s.taskId ?? taskId ?? '',
    parentSubtaskId: s.parentSubtaskId || null,
    categoryId: s.categoryId || '',
    title: s.title,
    description: s.description || '',
    priority: (s.priority || 'none') as Priority,
    completed: s.completed,
    dueDate: s.dueDate || 0,
    dueTime: s.dueTime || '',
    endTime: s.endTime || '',
    allDay: s.allDay ?? false,
    repeat: (s.repeat || 'none') as Repeat,
    repeatInterval: s.repeatInterval ?? 1,
    repeatDays: s.repeatDays || '',
    seriesId: s.seriesId || '',
    reminder: (s.reminder || 'none') as Reminder,
    assigneeId: s.assigneeId ?? null,
    order: s.order,
    subtasks: [],
  };
}

export async function fetchSubtaskTree(taskId: string): Promise<SubtaskData[]> {
  const topLevel = await collections.subtasks.query(Q.where('task_id', taskId), Q.where('parent_subtask_id', null)).fetch();
  const items: SubtaskData[] = topLevel.map((s: any) => mapSubtaskRow(s, taskId));

  const decorate = async (subtasks: SubtaskData[]): Promise<SubtaskData[]> => {
    for (const sub of subtasks) {
      const children = await collections.subtasks.query(Q.where('parent_subtask_id', sub.id)).fetch();
      if (children.length > 0) {
        sub.subtasks = await decorate(children.map((c: any) => mapSubtaskRow(c, taskId)));
      }
    }
    return subtasks;
  };

  return decorate(items);
}

function addDays(date: Date, days: number): Date {
  const next = new Date(date);
  next.setDate(next.getDate() + days);
  return next;
}

function addMonths(date: Date, months: number): Date {
  const next = new Date(date);
  const day = next.getDate();
  next.setDate(1);
  next.setMonth(next.getMonth() + months);
  const lastDay = new Date(next.getFullYear(), next.getMonth() + 1, 0).getDate();
  next.setDate(Math.min(day, lastDay));
  return next;
}

function startOfDay(date: Date): Date {
  const d = new Date(date);
  d.setHours(0, 0, 0, 0);
  return d;
}

function nextSelectedDay(base: Date, days: number[], intervalWeeks: number, todayStart: Date): Date {
  const msDay = 86400000;

  for (let offset = 1; offset <= intervalWeeks * 7 + 7; offset++) {
    const candidate = new Date(base.getTime() + offset * msDay);
    if (days.includes(candidate.getDay())) {
      const weeksFromBase = Math.floor(offset / 7);
      if (weeksFromBase % intervalWeeks === 0 && candidate.getTime() > todayStart.getTime()) {
        return candidate;
      }
    }
  }

  for (let offset = 1; offset <= 7 * intervalWeeks; offset++) {
    const candidate = new Date(todayStart.getTime() + offset * msDay);
    if (days.includes(candidate.getDay())) return candidate;
  }

  return addDays(todayStart, 7 * intervalWeeks);
}

export function parseRepeatDays(repeatDays: string): number[] {
  if (!repeatDays) return [];
  return repeatDays
    .split(',')
    .map((d) => parseInt(d, 10))
    .filter((d) => !Number.isNaN(d) && d >= 0 && d <= 6);
}

export function computeNextOccurrence(
  currentDueDate: number,
  repeat: Repeat,
  interval = 1,
  repeatDays = ''
): Date {
  const base = new Date(currentDueDate || Date.now());
  const todayStart = startOfDay(new Date());
  const effectiveInterval = Math.max(1, interval || 1);
  const days = parseRepeatDays(repeatDays);

  switch (repeat) {
    case 'daily': {
      let next = addDays(base, effectiveInterval);
      while (next.getTime() <= todayStart.getTime()) next = addDays(next, effectiveInterval);
      return next;
    }
    case 'monthly': {
      let next = addMonths(base, effectiveInterval);
      while (next.getTime() <= todayStart.getTime()) next = addMonths(next, effectiveInterval);
      return next;
    }
    case 'weekly':
      if (days.length === 0) {
        let next = addDays(base, 7 * effectiveInterval);
        while (next.getTime() <= todayStart.getTime()) next = addDays(next, 7 * effectiveInterval);
        return next;
      }
      return nextSelectedDay(base, days, effectiveInterval, todayStart);
    case 'custom':
      if (days.length === 0) {
        let next = addDays(base, 7 * effectiveInterval);
        while (next.getTime() <= todayStart.getTime()) next = addDays(next, 7 * effectiveInterval);
        return next;
      }
      return nextSelectedDay(base, days, effectiveInterval, todayStart);
    default:
      return new Date(currentDueDate || Date.now());
  }
}

function newSeriesId(): string {
  return `series_${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;
}

export async function deleteTaskWithSubtasks(taskId: string): Promise<void> {
  const subtasks = await collections.subtasks.query(Q.where('task_id', taskId)).fetch();
  for (const subtask of subtasks) {
    await subtask.destroyPermanently();
  }
  const task = await collections.tasks.find(taskId);
  await task.destroyPermanently();
  if (subtasks.length > 0) {
    await recordTombstonesInBatch('subtasks', subtasks.map((s) => s.id));
  }
  await recordTombstonesInBatch('tasks', [taskId]);
}

export type TaskDeleteScope = 'this' | 'future' | 'all';

export async function deleteTaskOccurrences(taskId: string, scope: TaskDeleteScope): Promise<void> {
  await database.write(async () => {
    const task = await collections.tasks.find(taskId);

    if (scope === 'this' || !task.seriesId || task.repeat === 'none') {
      await deleteTaskWithSubtasks(taskId);
      return;
    }

    const seriesTasks = await collections.tasks.query(Q.where('series_id', task.seriesId)).fetch();
    const anchor = task.dueDate || task.createdAt.getTime();

    const toDelete = seriesTasks.filter((t) => {
      if (scope === 'all') return true;
      return (t.dueDate || t.createdAt.getTime()) >= anchor;
    });

    for (const t of toDelete) {
      await deleteTaskWithSubtasks(t.id);
    }

    for (const t of toDelete) {
      await cancelTaskReminder(t.id);
    }
  });
}

export async function getSeriesOccurrenceCounts(taskId: string): Promise<{ future: number; all: number }> {
  const task = await collections.tasks.find(taskId);
  if (!task.seriesId || task.repeat === 'none') {
    return { future: 1, all: 1 };
  }
  const seriesTasks = await collections.tasks.query(Q.where('series_id', task.seriesId)).fetch();
  const anchor = task.dueDate || task.createdAt.getTime();
  const future = seriesTasks.filter((t) => (t.dueDate || t.createdAt.getTime()) >= anchor).length;
  return { future, all: seriesTasks.length };
}

export async function toggleTaskComplete(taskId: string): Promise<string | null> {
  let nextOccurrence: any = null;
  await database.write(async () => {
    const task = await collections.tasks.find(taskId);
    const completing = !task.completed;
    await task.update((t) => {
      t.completed = completing;
      t.completedAt = completing ? Date.now() : null;
      t.updatedAt = new Date();
    });
    if (completing && task.repeat !== 'none' && task.dueDate) {
      nextOccurrence = await createNextOccurrenceIfNeeded(task);
    }
  });
  if (nextOccurrence) await scheduleTaskReminder(nextOccurrence);
  const task = await collections.tasks.find(taskId);
  if (task.completed) await cancelTaskReminder(taskId);
  else await scheduleTaskReminder(task);
  return nextOccurrence ? nextOccurrence.id : null;
}

export async function toggleSubtaskComplete(subtaskId: string): Promise<void> {
  await database.write(async () => {
    const subtask = await collections.subtasks.find(subtaskId);
    await subtask.update((s) => {
      s.completed = !s.completed;
      s.updatedAt = new Date();
    });
    const task = await collections.tasks.find(subtask.taskId);
    await task.update((t) => {
      t.updatedAt = new Date();
    });
  });
  const subtask = await collections.subtasks.find(subtaskId);
  if (subtask.completed) await cancelTaskReminder(subtaskId);
  else await scheduleTaskReminder(subtask);
}

export interface SubtaskUpdateData {
  title: string;
  description?: string;
  categoryId?: string;
  priority: Priority;
  dueDate: number;
  dueTime?: string;
  endTime?: string;
  allDay?: boolean;
  repeat: Repeat;
  repeatInterval?: number;
  repeatDays?: string;
  reminder?: Reminder;
  assigneeId?: string | null;
}

export async function updateSubtask(subtaskId: string, data: SubtaskUpdateData): Promise<void> {
  await database.write(async () => {
    const subtask = await collections.subtasks.find(subtaskId);
    await subtask.update((s) => {
      s.title = data.title.trim();
      s.description = data.description || '';
      if (data.categoryId !== undefined) s.categoryId = data.categoryId;
      s.priority = data.priority;
      s.dueDate = data.dueDate;
      s.dueTime = data.dueTime || '';
      s.endTime = data.endTime || '';
      s.allDay = data.allDay ?? false;
      s.repeat = data.repeat;
      s.repeatInterval = data.repeatInterval || 1;
      s.repeatDays = data.repeatDays || '';
      s.reminder = data.reminder || 'none';
      s.assigneeId = data.assigneeId ?? null;
      s.updatedAt = new Date();
    });
    const task = await collections.tasks.find(subtask.taskId);
    await task.update((t) => {
      t.updatedAt = new Date();
    });
  });
  const subtask = await collections.subtasks.find(subtaskId);
  if (subtask.completed) await cancelTaskReminder(subtaskId);
  else await scheduleTaskReminder(subtask);
}

export async function deleteSubtask(subtaskId: string): Promise<void> {
  let parentTaskId: string | null = null;
  await database.write(async () => {
    const subtask = await collections.subtasks.find(subtaskId);
    parentTaskId = subtask.taskId;
    const children = await collections.subtasks.query(Q.where('parent_subtask_id', subtaskId)).fetch();
    for (const child of children) {
      await child.update((c) => {
        c.parentSubtaskId = null;
        c.updatedAt = new Date();
      });
    }
    await subtask.destroyPermanently();
    await recordTombstonesInBatch('subtasks', [subtaskId]);
  });
  await cancelTaskReminder(subtaskId);
  if (parentTaskId) {
    try {
      await database.write(async () => {
        const task = await collections.tasks.find(parentTaskId!);
        await task.update((t) => {
          t.updatedAt = new Date();
        });
      });
    } catch {
      // parent already gone
    }
  }
}

export async function duplicateSubtask(subtaskId: string): Promise<void> {
  let clone: any = null;
  await database.write(async () => {
    const subtask = await collections.subtasks.find(subtaskId);
    const siblings = await collections.subtasks.query(Q.where('task_id', subtask.taskId)).fetch();
    const now = new Date();

    clone = await collections.subtasks.create((s) => {
      s.taskId = subtask.taskId;
      s.categoryId = subtask.categoryId || '';
      s.title = subtask.title;
      s.description = subtask.description;
      s.priority = subtask.priority;
      s.completed = false;
      s.dueDate = subtask.dueDate;
      s.dueTime = subtask.dueTime;
      s.endTime = subtask.endTime || '';
      s.allDay = subtask.allDay ?? false;
      s.repeat = subtask.repeat || 'none';
      s.repeatInterval = subtask.repeatInterval || 1;
      s.repeatDays = subtask.repeatDays || '';
      s.seriesId = '';
      s.reminder = subtask.reminder || 'none';
      s.assigneeId = subtask.assigneeId ?? null;
      s.order = siblings.length;
      s.createdAt = now;
      s.updatedAt = now;
    });

    const task = await collections.tasks.find(subtask.taskId);
    await task.update((t) => {
      t.updatedAt = new Date();
    });
  });
  await scheduleTaskReminder(clone);
}

export async function setSubtaskPriority(subtaskId: string, priority: Priority): Promise<void> {
  await database.write(async () => {
    const subtask = await collections.subtasks.find(subtaskId);
    await subtask.update((s) => {
      s.priority = priority;
      s.updatedAt = new Date();
    });
    const task = await collections.tasks.find(subtask.taskId);
    await task.update((t) => {
      t.updatedAt = new Date();
    });
  });
}

export async function undoTaskComplete(taskId: string, nextOccurrenceId: string | null): Promise<void> {
  await database.write(async () => {
    if (nextOccurrenceId) {
      try {
        const occurrence = await collections.tasks.find(nextOccurrenceId);
        await deleteTaskWithSubtasks(occurrence.id);
        await cancelTaskReminder(occurrence.id);
      } catch {
        // occurrence already gone
      }
    }
    try {
      const task = await collections.tasks.find(taskId);
      if (task.completed) {
        await task.update((t) => {
          t.completed = false;
          t.updatedAt = new Date();
        });
      }
    } catch {
      // task already gone
    }
  });
  try {
    const task = await collections.tasks.find(taskId);
    await scheduleTaskReminder(task);
  } catch {
    // task already gone
  }
}

export async function deleteTask(taskId: string): Promise<void> {
  await database.write(async () => {
    await deleteTaskWithSubtasks(taskId);
  });
}

export async function convertTaskToSubtask(taskId: string, parentTaskId: string, parentSubtaskId: string | null = null): Promise<void> {
  if (taskId === parentTaskId) return;
  await database.write(async () => {
    const task = await collections.tasks.find(taskId);
    const ownSubtasks = await collections.subtasks.query(Q.where('task_id', taskId)).fetch();
    const existing = await collections.subtasks.query(
      Q.where('task_id', parentTaskId),
      parentSubtaskId ? Q.where('parent_subtask_id', parentSubtaskId) : Q.where('parent_subtask_id', null)
    ).fetch();
    const now = new Date();

    let order = existing.length;
    const created = await collections.subtasks.create((s) => {
      s.taskId = parentTaskId;
      s.parentSubtaskId = parentSubtaskId;
      s.categoryId = task.categoryId || '';
      s.title = task.title;
      s.description = task.description;
      s.priority = task.priority;
      s.completed = task.completed;
      s.dueDate = task.dueDate;
      s.dueTime = task.dueTime;
      s.endTime = task.endTime || '';
      s.allDay = task.allDay ?? false;
      s.repeat = task.repeat || 'none';
      s.repeatInterval = task.repeatInterval || 1;
      s.repeatDays = task.repeatDays || '';
      s.seriesId = task.seriesId || '';
      s.reminder = task.reminder || 'none';
      s.assigneeId = task.assigneeId ?? null;
      s.order = order++;
      s.createdAt = now;
      s.updatedAt = now;
    });

    for (const subtask of ownSubtasks) {
      await collections.subtasks.create((s) => {
        s.taskId = parentTaskId;
        s.parentSubtaskId = created.id;
        s.categoryId = subtask.categoryId || '';
        s.title = subtask.title;
        s.description = subtask.description;
        s.priority = subtask.priority;
        s.completed = subtask.completed;
        s.dueDate = subtask.dueDate;
        s.dueTime = subtask.dueTime;
        s.endTime = subtask.endTime || '';
        s.allDay = subtask.allDay ?? false;
        s.repeat = subtask.repeat || 'none';
        s.repeatInterval = subtask.repeatInterval || 1;
        s.repeatDays = subtask.repeatDays || '';
        s.seriesId = subtask.seriesId || '';
        s.reminder = subtask.reminder || 'none';
        s.assigneeId = subtask.assigneeId ?? null;
        s.order = order++;
        s.createdAt = now;
        s.updatedAt = now;
      });
    }

    const parent = await collections.tasks.find(parentTaskId);
    await parent.update((p) => {
      p.updatedAt = now;
    });

    await task.destroyPermanently();
    await recordTombstonesInBatch('tasks', [taskId]);
  });
}

export async function convertSubtaskToTask(subtaskId: string): Promise<void> {
  let newTaskId: string | null = null;
  await database.write(async () => {
    const subtask = await collections.subtasks.find(subtaskId);
    const parent = await collections.tasks.find(subtask.taskId);
    const now = new Date();

    const task = await collections.tasks.create((t) => {
      t.title = subtask.title;
      t.description = subtask.description || '';
      t.categoryId = subtask.categoryId || parent.categoryId || '';
      t.tags = tagsToString([subtask.categoryId || parent.categoryId].filter(Boolean));
      t.priority = subtask.priority;
      t.completed = subtask.completed;
      t.dueDate = subtask.dueDate;
      t.dueTime = subtask.dueTime || '';
      t.endTime = subtask.endTime || '';
      t.allDay = subtask.allDay ?? false;
      t.repeat = subtask.repeat || 'none';
      t.repeatInterval = subtask.repeatInterval || 1;
      t.repeatDays = subtask.repeatDays || '';
      t.seriesId = subtask.seriesId || '';
      t.reminder = subtask.reminder || 'none';
      t.assigneeId = subtask.assigneeId ?? null;
      t.createdAt = now;
      t.updatedAt = now;
    });
    newTaskId = task.id;

    const children = await collections.subtasks.query(Q.where('parent_subtask_id', subtaskId)).fetch();
    for (const child of children) {
      await child.update((c) => {
        c.parentSubtaskId = null;
        c.updatedAt = now;
      });
    }

    await subtask.destroyPermanently();
    await recordTombstonesInBatch('subtasks', [subtaskId]);
    await parent.update((p) => {
      p.updatedAt = now;
    });
  });
  await cancelTaskReminder(subtaskId);
  if (newTaskId) {
    const task = await collections.tasks.find(newTaskId);
    await scheduleTaskReminder(task);
  }
}

export async function moveSubtaskToTask(subtaskId: string, toTaskId: string): Promise<void> {
  if (!toTaskId) return;
  await database.write(async () => {
    const subtask = await collections.subtasks.find(subtaskId);
    if (subtask.taskId === toTaskId) return;
    const oldParentId = subtask.taskId;
    const siblings = await collections.subtasks.query(Q.where('task_id', toTaskId)).fetch();
    const now = new Date();

    await subtask.update((s) => {
      s.taskId = toTaskId;
      s.parentSubtaskId = null;
      s.order = siblings.length;
      s.updatedAt = now;
    });
    try {
      const oldParent = await collections.tasks.find(oldParentId);
      await oldParent.update((p) => {
        p.updatedAt = now;
      });
    } catch {
      // parent already gone
    }
    const newParent = await collections.tasks.find(toTaskId);
    await newParent.update((p) => {
      p.updatedAt = now;
    });
  });
}

export async function setSubtaskParent(subtaskId: string, newParentId: string): Promise<void> {
  if (subtaskId === newParentId) return;
  await database.write(async () => {
    const subtask = await collections.subtasks.find(subtaskId);
    if (subtask.parentSubtaskId === newParentId) return;

    let cursor: any = null;
    try {
      cursor = await collections.subtasks.find(newParentId);
    } catch {
      return;
    }
    const now = new Date();
    let guard = 0;
    while (cursor && guard++ < 200) {
      if (cursor.id === subtaskId) return;
      if (!cursor.parentSubtaskId) break;
      cursor = await collections.subtasks.find(cursor.parentSubtaskId);
    }

    const siblings = await collections.subtasks.query(
      Q.where('task_id', subtask.taskId),
      Q.where('parent_subtask_id', newParentId)
    ).fetch();

    await subtask.update((s) => {
      s.parentSubtaskId = newParentId;
      s.order = siblings.length;
      s.updatedAt = now;
    });

    const task = await collections.tasks.find(subtask.taskId);
    await task.update((t) => {
      t.updatedAt = now;
    });
  });
}

export async function setTaskCompleted(taskId: string, completed: boolean): Promise<void> {
  let nextOccurrence: any = null;
  await database.write(async () => {
    const task = await collections.tasks.find(taskId);
    await task.update((t) => {
      t.completed = completed;
      t.completedAt = completed ? Date.now() : null;
      t.updatedAt = new Date();
    });
    if (completed && task.repeat !== 'none' && task.dueDate) {
      nextOccurrence = await createNextOccurrenceIfNeeded(task);
    }
  });
  if (nextOccurrence) await scheduleTaskReminder(nextOccurrence);
  const task = await collections.tasks.find(taskId);
  if (task.completed) await cancelTaskReminder(taskId);
  else await scheduleTaskReminder(task);
}

async function createNextOccurrenceIfNeeded(task: any): Promise<any> {
  const seriesId = task.seriesId || newSeriesId();
  const existing = await collections.tasks.query(
    Q.where('series_id', seriesId),
    Q.where('completed', false)
  ).fetch();
  if (existing.length > 0) return null;
  const next = await createNextOccurrence(task, seriesId);
  if (!task.seriesId) {
    await task.update((t: any) => {
      t.seriesId = seriesId;
    });
  }
  return next;
}

async function createNextOccurrence(task: any, seriesId: string): Promise<any> {
  const nextDate = computeNextOccurrence(task.dueDate, task.repeat, task.repeatInterval, task.repeatDays);
  const subtasks = await collections.subtasks.query(Q.where('task_id', task.id)).fetch();
  const now = new Date();

  const next = await collections.tasks.create((t) => {
    t.title = task.title;
    t.description = task.description;
    t.categoryId = task.categoryId;
    t.tags = task.tags || '';
    t.priority = task.priority;
    t.completed = false;
    t.dueDate = nextDate.getTime();
    t.dueTime = task.dueTime;
    t.endTime = task.endTime || '';
    t.allDay = task.allDay ?? false;
    t.repeat = task.repeat;
    t.repeatInterval = task.repeatInterval || 1;
    t.repeatDays = task.repeatDays || '';
    t.seriesId = seriesId;
    t.reminder = task.reminder || 'none';
    t.assigneeId = task.assigneeId ?? null;
    t.createdAt = now;
    t.updatedAt = now;
  });

  for (const subtask of subtasks) {
    await collections.subtasks.create((s) => {
      s.taskId = next.id;
      s.title = subtask.title;
      s.description = subtask.description;
      s.priority = subtask.priority;
      s.completed = false;
      s.dueDate = subtask.dueDate;
      s.dueTime = subtask.dueTime;
      s.endTime = subtask.endTime || '';
      s.allDay = subtask.allDay ?? false;
      s.reminder = subtask.reminder || 'none';
      s.assigneeId = subtask.assigneeId ?? null;
      s.order = subtask.order;
      s.createdAt = now;
      s.updatedAt = now;
    });
  }

  return next;
}

export async function setTaskCategory(taskId: string, categoryId: string): Promise<void> {
  await database.write(async () => {
    const task = await collections.tasks.find(taskId);
    await task.update((t) => {
      t.categoryId = categoryId;
      t.tags = tagsToString(categoryId ? [categoryId] : []);
      t.updatedAt = new Date();
    });
  });
}

export async function setTaskPriority(taskId: string, priority: Priority): Promise<void> {
  await database.write(async () => {
    const task = await collections.tasks.find(taskId);
    await task.update((t) => {
      t.priority = priority;
      t.updatedAt = new Date();
    });
  });
}

export async function duplicateTask(taskId: string): Promise<void> {
  let clone: any = null;
  await database.write(async () => {
    const task = await collections.tasks.find(taskId);
    const subtasks = await collections.subtasks.query(Q.where('task_id', taskId)).fetch();
    const now = new Date();

    clone = await collections.tasks.create((t) => {
      t.title = task.title;
      t.description = task.description;
      t.categoryId = task.categoryId;
      t.tags = task.tags || '';
      t.priority = task.priority;
      t.completed = false;
      t.dueDate = task.dueDate;
      t.dueTime = task.dueTime;
      t.endTime = task.endTime || '';
      t.allDay = task.allDay ?? false;
      t.repeat = task.repeat;
      t.repeatInterval = task.repeatInterval || 1;
      t.repeatDays = task.repeatDays || '';
      t.seriesId = '';
      t.reminder = task.reminder || 'none';
      t.assigneeId = task.assigneeId ?? null;
      t.createdAt = now;
      t.updatedAt = now;
    });

    for (const subtask of subtasks) {
      await collections.subtasks.create((s) => {
        s.taskId = clone.id;
        s.title = subtask.title;
        s.description = subtask.description;
        s.priority = subtask.priority;
        s.completed = false;
        s.dueDate = subtask.dueDate;
        s.dueTime = subtask.dueTime;
        s.endTime = subtask.endTime || '';
        s.allDay = subtask.allDay ?? false;
        s.reminder = subtask.reminder || 'none';
        s.assigneeId = subtask.assigneeId ?? null;
        s.order = subtask.order;
        s.createdAt = now;
        s.updatedAt = now;
      });
    }
  });
  await scheduleTaskReminder(clone);
}

export async function reorderTasks(taskIds: string[]): Promise<void> {
  await database.write(async () => {
    const now = new Date();
    for (let i = 0; i < taskIds.length; i++) {
      const task = await collections.tasks.find(taskIds[i]);
      await task.update((t) => {
        t.order = i;
        t.updatedAt = now;
      });
    }
  });
}

export interface CreateSubtaskData {
  taskId: string;
  parentSubtaskId?: string | null;
  categoryId?: string;
  title: string;
  description?: string;
  priority?: Priority;
  dueDate?: number;
  dueTime?: string;
  endTime?: string;
  allDay?: boolean;
  repeat?: Repeat;
  repeatInterval?: number;
  repeatDays?: string;
  reminder?: Reminder;
  assigneeId?: string | null;
}

export async function createSubtask(data: CreateSubtaskData): Promise<string> {
  let newSubtaskId: string | null = null;
  await database.write(async () => {
    const now = new Date();
    const siblings = await collections.subtasks.query(
      Q.where('task_id', data.taskId),
      data.parentSubtaskId ? Q.where('parent_subtask_id', data.parentSubtaskId) : Q.where('parent_subtask_id', null)
    ).fetch();

    const subtask = await collections.subtasks.create((s) => {
      s.taskId = data.taskId;
      s.parentSubtaskId = data.parentSubtaskId || null;
      s.categoryId = data.categoryId || '';
      s.title = data.title.trim();
      s.description = data.description || '';
      s.priority = data.priority || 'none';
      s.completed = false;
      s.dueDate = data.dueDate || 0;
      s.dueTime = data.dueTime || '';
      s.endTime = data.endTime || '';
      s.allDay = data.allDay ?? false;
      s.repeat = data.repeat || 'none';
      s.repeatInterval = data.repeatInterval || 1;
      s.repeatDays = data.repeatDays || '';
      s.seriesId = '';
      s.reminder = data.reminder || 'none';
      s.assigneeId = data.assigneeId ?? null;
      s.order = siblings.length;
      s.createdAt = now;
      s.updatedAt = now;
    });
    newSubtaskId = subtask.id;
  });
  return newSubtaskId!;
}
