import { Prisma } from '@prisma/client';
import {
  ConflictException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateTagGroupDto } from './dto/create-tag-group.dto';
import { UpdateTagGroupDto } from './dto/update-tag-group.dto';
import { ReorderTagGroupsDto } from './dto/reorder-tag-groups.dto';

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

  findAll() {
    return this.prisma.tagGroup.findMany({
      orderBy: [{ sortOrder: 'asc' }, { id: 'asc' }],
      include: { _count: { select: { tags: true } } },
    });
  }

  async findOne(id: bigint) {
    const g = await this.prisma.tagGroup.findUnique({
      where: { id },
      include: { _count: { select: { tags: true } } },
    });
    if (!g) throw new NotFoundException(`TagGroup ${id} not found`);
    return g;
  }

  async create(dto: CreateTagGroupDto) {
    try {
      return await this.prisma.tagGroup.create({
        data: {
          groupName: dto.groupName,
          groupIcon: dto.groupIcon ?? null,
          groupColor: dto.groupColor ?? null,
          sortOrder: dto.sortOrder ?? 0,
        },
      });
    } catch (err) {
      if (
        err instanceof Prisma.PrismaClientKnownRequestError &&
        err.code === 'P2002'
      ) {
        throw new ConflictException('Tag group name already exists');
      }
      throw err;
    }
  }

  async update(id: bigint, dto: UpdateTagGroupDto) {
    await this.findOne(id);
    const data: Prisma.TagGroupUpdateInput = {};
    if (dto.groupName !== undefined) data.groupName = dto.groupName;
    if (dto.groupIcon !== undefined) data.groupIcon = dto.groupIcon;
    if (dto.groupColor !== undefined) data.groupColor = dto.groupColor;
    if (dto.sortOrder !== undefined) data.sortOrder = dto.sortOrder;
    try {
      return await this.prisma.tagGroup.update({ where: { id }, data });
    } catch (err) {
      if (
        err instanceof Prisma.PrismaClientKnownRequestError &&
        err.code === 'P2002'
      ) {
        throw new ConflictException('Tag group name already exists');
      }
      throw err;
    }
  }

  async remove(id: bigint) {
    await this.findOne(id);
    return this.prisma.tagGroup.delete({ where: { id } });
  }

  async reorder(dto: ReorderTagGroupsDto) {
    return this.prisma.$transaction(
      dto.items.map((item) =>
        this.prisma.tagGroup.update({
          where: { id: BigInt(item.id) },
          data: { sortOrder: item.sortOrder },
        }),
      ),
    );
  }
}
