import { Prisma } from '@prisma/client';
import { prisma } from '../../config/database';
import { AppError } from '../../middleware/error-handler';
import type {
  CreateAgendaInput,
  UpdateAgendaInput,
  CreateMinutesInput,
  UpdateMinutesInput,
  ListAgendasInput,
} from './agenda.schemas';

export const agendaService = {
  async findAll(filters: ListAgendasInput) {
    const { page, limit, search, status } = filters;
    const where: Prisma.MeetingAgendaWhereInput = {};

    if (status) where.status = status;
    if (search) {
      where.title = { contains: search, mode: 'insensitive' };
    }

    const [agendas, total] = await Promise.all([
      prisma.meetingAgenda.findMany({
        where,
        include: {
          createdBy: { select: { id: true, name: true, email: true } },
          shift: { select: { id: true, title: true, date: true } },
          poll: { select: { id: true, title: true } },
          _count: { select: { actionItems: true } },
        },
        orderBy: { createdAt: 'desc' },
        skip: (page - 1) * limit,
        take: limit,
      }),
      prisma.meetingAgenda.count({ where }),
    ]);

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

  async findById(id: string) {
    const agenda = await prisma.meetingAgenda.findUnique({
      where: { id },
      include: {
        createdBy: { select: { id: true, name: true, email: true } },
        shift: { select: { id: true, title: true, date: true } },
        poll: { select: { id: true, title: true } },
        minutes: {
          include: {
            createdBy: { select: { id: true, name: true } },
            approvedBy: { select: { id: true, name: true } },
          },
        },
        actionItems: {
          include: {
            assignee: { select: { id: true, name: true, email: true } },
            createdBy: { select: { id: true, name: true } },
          },
          orderBy: { createdAt: 'asc' },
        },
      },
    });
    if (!agenda) throw new AppError(404, 'Agenda not found');
    return agenda;
  },

  async create(data: CreateAgendaInput, userId: string) {
    return prisma.meetingAgenda.create({
      data: {
        title: data.title,
        shiftId: data.shiftId,
        pollId: data.pollId,
        items: data.items as unknown as Prisma.InputJsonValue,
        createdByUserId: userId,
      },
      include: {
        createdBy: { select: { id: true, name: true, email: true } },
      },
    });
  },

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

    const updateData: Prisma.MeetingAgendaUncheckedUpdateInput = {};
    if (data.title !== undefined) updateData.title = data.title;
    if (data.items !== undefined) updateData.items = data.items as unknown as Prisma.InputJsonValue;
    if (data.status !== undefined) updateData.status = data.status;

    return prisma.meetingAgenda.update({
      where: { id },
      data: updateData,
      include: {
        createdBy: { select: { id: true, name: true, email: true } },
      },
    });
  },

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

  async createMinutes(data: CreateMinutesInput, userId: string) {
    const agenda = await prisma.meetingAgenda.findUnique({ where: { id: data.agendaId } });
    if (!agenda) throw new AppError(404, 'Agenda not found');

    const existing = await prisma.meetingMinutes.findUnique({ where: { agendaId: data.agendaId } });
    if (existing) throw new AppError(400, 'Minutes already exist for this agenda');

    return prisma.meetingMinutes.create({
      data: {
        agendaId: data.agendaId,
        notes: data.notes,
        decisions: data.decisions as unknown as Prisma.InputJsonValue,
        attendees: data.attendees as unknown as Prisma.InputJsonValue,
        createdByUserId: userId,
      },
      include: {
        createdBy: { select: { id: true, name: true } },
      },
    });
  },

  async updateMinutes(id: string, data: UpdateMinutesInput) {
    const existing = await prisma.meetingMinutes.findUnique({ where: { id } });
    if (!existing) throw new AppError(404, 'Minutes not found');

    const updateData: Prisma.MeetingMinutesUncheckedUpdateInput = {};
    if (data.notes !== undefined) updateData.notes = data.notes;
    if (data.decisions !== undefined) updateData.decisions = data.decisions as unknown as Prisma.InputJsonValue;
    if (data.attendees !== undefined) updateData.attendees = data.attendees as unknown as Prisma.InputJsonValue;

    return prisma.meetingMinutes.update({
      where: { id },
      data: updateData,
      include: {
        createdBy: { select: { id: true, name: true } },
        approvedBy: { select: { id: true, name: true } },
      },
    });
  },

  async approveMinutes(id: string, userId: string) {
    const existing = await prisma.meetingMinutes.findUnique({ where: { id } });
    if (!existing) throw new AppError(404, 'Minutes not found');
    if (existing.approvedAt) throw new AppError(400, 'Minutes are already approved');

    return prisma.meetingMinutes.update({
      where: { id },
      data: {
        approvedAt: new Date(),
        approvedByUserId: userId,
      },
      include: {
        createdBy: { select: { id: true, name: true } },
        approvedBy: { select: { id: true, name: true } },
      },
    });
  },
};
