import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common';
import { PrismaService } from '@chatapp/database';

@Injectable()
export class ListsService {
  constructor(private readonly prisma: PrismaService) {}

  async listByChannel(channelId: string, wsId: string) {
    const lists = await this.prisma.list.findMany({
      where: { channelId, workspaceId: wsId },
      orderBy: { createdAt: 'asc' },
      include: {
        _count: { select: { items: true } },
        createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
      },
    });

    return {
      lists: lists.map(l => ({
        id: l.id,
        name: l.name,
        description: l.description,
        view_type: l.viewType,
        channel_id: l.channelId,
        created_by: l.createdByUser,
        item_count: l._count.items,
        created_at: l.createdAt,
        updated_at: l.updatedAt,
      })),
    };
  }

  async create(channelId: string, wsId: string, userId: string, dto: any) {
    const list = await this.prisma.list.create({
      data: {
        workspaceId: wsId,
        channelId,
        name: dto.name,
        description: dto.description,
        viewType: dto.view_type || 'table',
        groupByField: dto.group_by_field,
        createdBy: userId,
        fields: dto.fields
          ? {
              create: dto.fields.map((f: any, i: number) => ({
                name: f.name,
                fieldType: f.field_type || f.type,
                options: f.options || undefined,
                orderIndex: f.order_index ?? i,
                isRequired: f.is_required ?? false,
              })),
            }
          : undefined,
      },
      include: { fields: { orderBy: { orderIndex: 'asc' } } },
    });

    return list;
  }

  async findById(id: string, wsId: string) {
    const list = await this.prisma.list.findFirst({
      where: { id, workspaceId: wsId },
      include: {
        fields: { orderBy: { orderIndex: 'asc' } },
        items: {
          orderBy: { orderIndex: 'asc' },
          include: {
            createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
            comments: {
              orderBy: { createdAt: 'asc' },
              include: {
                user: { select: { id: true, displayName: true, avatarUrl: true } },
              },
            },
          },
        },
        createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
      },
    });

    if (!list) throw new NotFoundException('List not found');

    return {
      id: list.id,
      name: list.name,
      description: list.description,
      view_type: list.viewType,
      group_by_field: list.groupByField,
      created_by: list.createdByUser,
      created_at: list.createdAt,
      updated_at: list.updatedAt,
      fields: list.fields.map(f => ({
        id: f.id,
        name: f.name,
        field_type: f.fieldType,
        options: f.options,
        order_index: f.orderIndex,
        is_required: f.isRequired,
      })),
      items: list.items.map(item => ({
        id: item.id,
        name: item.name,
        field_values: item.fieldValues,
        order_index: item.orderIndex,
        completed_at: item.completedAt,
        created_by: item.createdByUser,
        created_at: item.createdAt,
        updated_at: item.updatedAt,
        comments: item.comments.map(c => ({
          id: c.id,
          text: c.text,
          user: c.user,
          created_at: c.createdAt,
        })),
      })),
    };
  }

  async addItem(listId: string, wsId: string, userId: string, dto: any) {
    const list = await this.prisma.list.findFirst({ where: { id: listId, workspaceId: wsId } });
    if (!list) throw new NotFoundException('List not found');

    const maxOrder = await this.prisma.listItem.aggregate({
      where: { listId },
      _max: { orderIndex: true },
    });

    const item = await this.prisma.listItem.create({
      data: {
        listId,
        name: dto.name,
        fieldValues: dto.field_values || {},
        orderIndex: dto.order_index ?? (maxOrder._max.orderIndex ?? -1) + 1,
        createdBy: userId,
      },
      include: {
        createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
      },
    });

    return item;
  }

  async updateItem(listId: string, itemId: string, userId: string, dto: any) {
    const item = await this.prisma.listItem.findFirst({
      where: { id: itemId, listId },
    });
    if (!item) throw new NotFoundException('Item not found');

    const data: any = {};
    if (dto.name !== undefined) data.name = dto.name;
    if (dto.field_values !== undefined) data.fieldValues = dto.field_values;
    if (dto.order_index !== undefined) data.orderIndex = dto.order_index;

    // Handle status / completed_at via field_values or explicit
    if (dto.status === 'completed' || dto.completed) {
      data.completedAt = new Date();
    } else if (dto.status === 'incomplete' || dto.completed === false) {
      data.completedAt = null;
    }

    // Handle assigned user via field_values
    if (dto.assigned_to !== undefined) {
      const currentValues = item.fieldValues as any;
      data.fieldValues = { ...currentValues, assigned_to: dto.assigned_to };
    }

    return this.prisma.listItem.update({
      where: { id: itemId },
      data,
      include: {
        createdByUser: { select: { id: true, displayName: true, avatarUrl: true } },
      },
    });
  }

  async deleteItem(listId: string, itemId: string) {
    const item = await this.prisma.listItem.findFirst({
      where: { id: itemId, listId },
    });
    if (!item) throw new NotFoundException('Item not found');

    await this.prisma.listItem.delete({ where: { id: itemId } });
    return { deleted: true };
  }

  async addComment(listId: string, itemId: string, userId: string, dto: any) {
    const item = await this.prisma.listItem.findFirst({
      where: { id: itemId, listId },
    });
    if (!item) throw new NotFoundException('Item not found');

    const comment = await this.prisma.listItemComment.create({
      data: {
        listItemId: itemId,
        userId,
        text: dto.text,
      },
      include: {
        user: { select: { id: true, displayName: true, avatarUrl: true } },
      },
    });

    return comment;
  }
}