import { Prisma } from '@prisma/client';
import { prisma } from '../../config/database';
import { AppError } from '../../middleware/error-handler';
import type {
  CreateActionItemInput,
  UpdateActionItemInput,
  ListActionItemsInput,
} from './action-items.schemas';

const actionItemInclude = {
  assignee: { select: { id: true, name: true, email: true } },
  createdBy: { select: { id: true, name: true } },
  agenda: { select: { id: true, title: true } },
} as const;

export const actionItemsService = {
  async findAll(filters: ListActionItemsInput) {
    const { page, limit, search, status, assigneeUserId, overdue } = filters;
    const where: Prisma.ActionItemWhereInput = {};

    if (status) where.status = status;
    if (assigneeUserId) where.assigneeUserId = assigneeUserId;
    if (search) {
      where.OR = [
        { title: { contains: search, mode: 'insensitive' } },
        { description: { contains: search, mode: 'insensitive' } },
      ];
    }
    if (overdue) {
      where.dueDate = { lt: new Date() };
      where.status = { not: 'done' };
    }

    const [items, total] = await Promise.all([
      prisma.actionItem.findMany({
        where,
        include: actionItemInclude,
        orderBy: { createdAt: 'desc' },
        skip: (page - 1) * limit,
        take: limit,
      }),
      prisma.actionItem.count({ where }),
    ]);

    return {
      actionItems: items,
      pagination: {
        page,
        limit,
        total,
        totalPages: Math.ceil(total / limit),
      },
    };
  },

  async findById(id: string) {
    const item = await prisma.actionItem.findUnique({
      where: { id },
      include: actionItemInclude,
    });
    if (!item) throw new AppError(404, 'Action item not found');
    return item;
  },

  async findByUser(userId: string, status?: string) {
    const where: Prisma.ActionItemWhereInput = {
      assigneeUserId: userId,
      status: status ? status : { not: 'done' },
    };

    const items = await prisma.actionItem.findMany({
      where,
      include: actionItemInclude,
      orderBy: [{ dueDate: 'asc' }, { createdAt: 'desc' }],
    });

    return {
      actionItems: items,
      pagination: { page: 1, limit: items.length, total: items.length, totalPages: 1 },
    };
  },

  async create(data: CreateActionItemInput, userId: string) {
    return prisma.actionItem.create({
      data: {
        title: data.title,
        description: data.description,
        agendaId: data.agendaId,
        assigneeUserId: data.assigneeUserId,
        dueDate: data.dueDate ? new Date(data.dueDate) : null,
        priority: data.priority,
        createdByUserId: userId,
      },
      include: actionItemInclude,
    });
  },

  async update(id: string, data: UpdateActionItemInput) {
    const existing = await prisma.actionItem.findUnique({ where: { id } });
    if (!existing) throw new AppError(404, 'Action item not found');

    const updateData: Prisma.ActionItemUncheckedUpdateInput = {};
    if (data.title !== undefined) updateData.title = data.title;
    if (data.description !== undefined) updateData.description = data.description;
    if (data.assigneeUserId !== undefined) updateData.assigneeUserId = data.assigneeUserId;
    if (data.dueDate !== undefined) updateData.dueDate = data.dueDate ? new Date(data.dueDate) : null;
    if (data.priority !== undefined) updateData.priority = data.priority;
    if (data.status !== undefined) {
      updateData.status = data.status;
      if (data.status === 'done' && existing.status !== 'done') {
        updateData.completedAt = new Date();
      } else if (data.status !== 'done' && existing.status === 'done') {
        updateData.completedAt = null;
      }
    }

    return prisma.actionItem.update({
      where: { id },
      data: updateData,
      include: actionItemInclude,
    });
  },

  async delete(id: string) {
    const existing = await prisma.actionItem.findUnique({ where: { id } });
    if (!existing) throw new AppError(404, 'Action item not found');
    await prisma.actionItem.delete({ where: { id } });
  },

  async getOverdue() {
    return prisma.actionItem.findMany({
      where: {
        dueDate: { lt: new Date() },
        status: { not: 'done' },
      },
      include: actionItemInclude,
      orderBy: { dueDate: 'asc' },
    });
  },
};
