import { Router, Request, Response } from 'express';
import { asyncHandler } from '../utils/asyncHandler';
import { db } from '../db';
import { subtasks, tasks } from '../db/schema';
import { eq, and, asc, desc, isNull } from 'drizzle-orm';
import { authMiddleware } from '../utils/auth';
import { AppError } from '../middleware/errorHandler';
import { subtaskCreateSchema, subtaskUpdateSchema } from '../utils/validation';

const router = Router();

router.use(authMiddleware);

// Helper to build nested subtask tree
const buildSubtaskTree = (allSubtasks: any[], parentId: string | null = null): any[] => {
  return allSubtasks
    .filter((s) => s.parentSubtaskId === parentId)
    .sort((a, b) => a.order - b.order)
    .map((s) => ({
      ...s,
      subtasks: buildSubtaskTree(allSubtasks, s.id),
    }));
};

router.get('/task/:taskId', asyncHandler(async (req: Request, res: Response) => {
  const userId = req.user!.userId;

  // Verify task exists and belongs to user
  const task = await db
    .select()
    .from(tasks)
    .where(and(eq(tasks.id, req.params.taskId), eq(tasks.userId, userId)))
    .limit(1);

  if (task.length === 0) {
    throw new AppError('NOT_FOUND', 'Task not found', 404);
  }

  const taskSubtasks = await db
    .select()
    .from(subtasks)
    .where(and(eq(subtasks.taskId, req.params.taskId), eq(subtasks.userId, userId)))
    .orderBy(asc(subtasks.order));

  const nestedSubtasks = buildSubtaskTree(taskSubtasks);

  res.json({ subtasks: nestedSubtasks });
}));

router.post('/task/:taskId', asyncHandler(async (req: Request, res: Response) => {
  const data = subtaskCreateSchema.parse(req.body);
  const userId = req.user!.userId;

  const task = await db
    .select()
    .from(tasks)
    .where(and(eq(tasks.id, req.params.taskId), eq(tasks.userId, userId)))
    .limit(1);

  if (task.length === 0) {
    throw new AppError('NOT_FOUND', 'Task not found', 404);
  }

  const now = Date.now();
  const parentSubtaskId = data.parentSubtaskId || null;
  
  const maxOrder = await db
    .select({ order: subtasks.order })
    .from(subtasks)
    .where(and(
      eq(subtasks.taskId, req.params.taskId), 
      eq(subtasks.userId, userId),
      parentSubtaskId ? eq(subtasks.parentSubtaskId, parentSubtaskId) : isNull(subtasks.parentSubtaskId)
    ))
    .orderBy(desc(subtasks.order))
    .limit(1);

  const subtaskId = `sub_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;
  
  const newSubtask = {
    id: subtaskId,
    userId,
    taskId: req.params.taskId,
    parentSubtaskId,
    categoryId: data.categoryId ?? null,
    title: data.title,
    description: data.description ?? '',
    priority: data.priority ?? 'none',
    completed: false,
    dueDate: data.dueDate ?? 0,
    dueTime: data.dueTime ?? '',
    endTime: data.endTime ?? '',
    allDay: data.allDay ?? false,
    repeat: data.repeat ?? 'none',
    repeatInterval: data.repeatInterval ?? 1,
    repeatDays: data.repeatDays ?? '',
    seriesId: data.seriesId ?? '',
    reminder: data.reminder ?? 'none',
    reminders: data.reminders ?? '',
    assigneeId: data.assigneeId ?? null,
    order: data.order ?? (maxOrder[0]?.order ?? -1) + 1,
    createdAt: now,
    updatedAt: now,
  };

  await db.insert(subtasks).values(newSubtask);

  // Update task updatedAt
  await db
    .update(tasks)
    .set({ updatedAt: now })
    .where(and(eq(tasks.id, req.params.taskId), eq(tasks.userId, userId)));

  res.status(201).json(newSubtask);
}));

router.patch('/:id', asyncHandler(async (req: Request, res: Response) => {
  const data = subtaskUpdateSchema.parse(req.body);
  const userId = req.user!.userId;

  const existing: any[] = await db
    .select()
    .from(subtasks)
    .where(and(eq(subtasks.id, req.params.id), eq(subtasks.userId, userId)))
    .limit(1);

  if (existing.length === 0) {
    throw new AppError('NOT_FOUND', 'Subtask not found', 404);
  }

  const now = Date.now();
  const updated = await db
    .update(subtasks)
    .set({ ...data, updatedAt: now })
    .where(and(eq(subtasks.id, req.params.id), eq(subtasks.userId, userId)))
    .returning();

  // Update task updatedAt
  await db
    .update(tasks)
    .set({ updatedAt: now })
    .where(and(eq(tasks.id, existing[0].taskId), eq(tasks.userId, userId)));

  res.json(updated[0]);
}));

router.delete('/:id', asyncHandler(async (req: Request, res: Response) => {
  const userId = req.user!.userId;

  const existing = await db
    .select()
    .from(subtasks)
    .where(and(eq(subtasks.id, req.params.id), eq(subtasks.userId, userId)))
    .limit(1);

  if (existing.length === 0) {
    throw new AppError('NOT_FOUND', 'Subtask not found', 404);
  }

  const taskId = existing[0].taskId;

  await db
    .delete(subtasks)
    .where(and(eq(subtasks.id, req.params.id), eq(subtasks.userId, userId)));

  // Update task updatedAt
  await db
    .update(tasks)
    .set({ updatedAt: Date.now() })
    .where(and(eq(tasks.id, taskId), eq(tasks.userId, userId)));

  res.status(204).send();
}));

export default router;