import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { OrgRole } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';

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

  listForUser(userId: string) {
    return this.prisma.organization.findMany({
      where: { memberships: { some: { userId } } },
      select: {
        id: true,
        name: true,
        slug: true,
        createdAt: true,
        memberships: { where: { userId }, select: { role: true } },
        _count: { select: { jobs: true, devices: true } },
      },
      orderBy: { createdAt: 'asc' },
    });
  }

  rename(orgId: string, name: string) {
    return this.prisma.organization.update({ where: { id: orgId }, data: { name } });
  }

  listMembers(orgId: string) {
    return this.prisma.orgMembership.findMany({
      where: { orgId },
      select: {
        role: true,
        createdAt: true,
        user: { select: { id: true, email: true, name: true } },
      },
      orderBy: { createdAt: 'asc' },
    });
  }

  async addMember(orgId: string, email: string, role: OrgRole) {
    const user = await this.prisma.user.findUnique({ where: { email } });
    if (!user) {
      throw new NotFoundException('No account exists with that email (they must register first)');
    }
    const existing = await this.prisma.orgMembership.findUnique({
      where: { orgId_userId: { orgId, userId: user.id } },
    });
    if (existing) {
      throw new BadRequestException('Already a member of this organization');
    }
    return this.prisma.orgMembership.create({
      data: { orgId, userId: user.id, role },
      select: { role: true, user: { select: { id: true, email: true, name: true } } },
    });
  }

  async updateMember(orgId: string, userId: string, role: OrgRole) {
    await this.assertNotLastAdmin(orgId, userId);
    return this.prisma.orgMembership.update({
      where: { orgId_userId: { orgId, userId } },
      data: { role },
      select: { role: true, user: { select: { id: true, email: true, name: true } } },
    });
  }

  async removeMember(orgId: string, userId: string) {
    await this.assertNotLastAdmin(orgId, userId);
    await this.prisma.orgMembership.delete({
      where: { orgId_userId: { orgId, userId } },
    });
    return { ok: true };
  }

  // Refuse to demote/remove the only remaining admin so the org can't be orphaned.
  private async assertNotLastAdmin(orgId: string, userId: string) {
    const target = await this.prisma.orgMembership.findUnique({
      where: { orgId_userId: { orgId, userId } },
    });
    if (!target) {
      throw new NotFoundException('Membership not found');
    }
    if (target.role !== 'ORG_ADMIN') {
      return;
    }
    const admins = await this.prisma.orgMembership.count({
      where: { orgId, role: 'ORG_ADMIN' },
    });
    if (admins <= 1) {
      throw new BadRequestException('Cannot demote or remove the last organization admin');
    }
  }
}
