import { ConflictException, ForbiddenException, Injectable } from '@nestjs/common';
import { AccountStatus, EstateSignupStatus, EstateStatus, Prisma, SubscriptionStatus, UserRole } from '@prisma/client';
import { AuditService } from '../audit/audit.service';
import { RequestUser } from '../common/request-user';
import { PrismaService } from '../database/prisma.service';
import { CreateEstateDto } from './dto/create-estate.dto';

@Injectable()
export class EstatesService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly audit: AuditService
  ) {}

  findAll(user: RequestUser) {
    if (user.role === UserRole.SUPER_ADMIN) {
      return this.prisma.estate.findMany({ orderBy: { createdAt: 'desc' } });
    }
    if (user.role === UserRole.SALES_ADMIN) {
      return this.prisma.estate.findMany({
        where: { salesPartnerId: user.id },
        orderBy: { createdAt: 'desc' },
        include: { users: { where: { role: UserRole.ESTATE_ADMIN }, take: 3 } }
      });
    }
    if (!user.estateId) {
      throw new ForbiddenException('Estate-scoped user is missing an estate');
    }
    return this.prisma.estate.findMany({ where: { id: user.estateId } });
  }

  async create(dto: CreateEstateDto, user: RequestUser) {
    if (user.role !== UserRole.SUPER_ADMIN && user.role !== UserRole.SALES_ADMIN) {
      throw new ForbiddenException('Only platform admins can onboard estates');
    }

    const estate = await this.createEstateWithOptionalAdmin(dto, user);
    await this.audit.record({
      estateId: estate.id,
      actorType: 'USER',
      actorId: user.id,
      action: 'ESTATE_CREATED',
      metadata: { name: estate.name, salesPartnerId: estate.salesPartnerId ?? null }
    });
    return estate;
  }

  private async createEstateWithOptionalAdmin(dto: CreateEstateDto, user: RequestUser) {
    try {
      return await this.prisma.$transaction(async (tx) => {
        const estate = await tx.estate.create({
          data: {
            name: dto.name,
            location: dto.location,
            unitCount: dto.unitCount ?? 0,
            estateType: dto.estateType,
            status: EstateStatus.ACTIVE,
            signupStatus: EstateSignupStatus.APPROVED,
            subscriptionStatus: SubscriptionStatus.NONE,
            activatedAt: new Date(),
            salesPartnerId: user.role === UserRole.SALES_ADMIN ? user.id : undefined,
            settings: {
              ...(dto.settings ?? {}),
              onboarding: {
                adminEmail: dto.adminEmail ?? null
              }
            } as Prisma.InputJsonValue,
            branding: (dto.branding ?? {}) as Prisma.InputJsonValue
          }
        });

        if (user.role === UserRole.SALES_ADMIN) {
          await tx.salesPartnerProfile.upsert({
            where: { salesAdminId: user.id },
            create: { salesAdminId: user.id, enabled: false, updatedById: user.id },
            update: {}
          });
        }

        if (dto.adminName && dto.adminPhone) {
          await tx.user.create({
            data: {
              estateId: estate.id,
              phone: dto.adminPhone,
              name: dto.adminName,
              role: UserRole.ESTATE_ADMIN,
              status: AccountStatus.ACTIVE
            }
          });
        }

        return estate;
      });
    } catch (error) {
      if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2002') {
        throw new ConflictException('A user with this phone number already exists');
      }
      throw error;
    }
  }
}
