import { ForbiddenException, Injectable, NotFoundException } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from '../../../prisma/prisma.service';
import { AuthenticatedUser } from '../../../common/decorators/current-user.decorator';

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

  private async assertBudgetAccess(user: AuthenticatedUser, budgetId: string) {
    const b = await this.prisma.budget.findUnique({
      where: { id: budgetId },
      include: { fiscalYear: { include: { complex: true } } },
    });
    if (!b) throw new NotFoundException('Budget not found');
    if (!user.isSuperAdmin && b.fiscalYear.complex.tenantId !== user.tenantId) {
      throw new ForbiddenException();
    }
    return b;
  }

  async createLine(
    user: AuthenticatedUser,
    budgetId: string,
    dto: { category: string; repartitionKeyId: string; estimatedAmount: number; notes?: string },
  ) {
    await this.assertBudgetAccess(user, budgetId);
    return this.prisma.budgetLine.create({
      data: {
        budgetId,
        category: dto.category,
        repartitionKeyId: dto.repartitionKeyId,
        estimatedAmount: new Prisma.Decimal(dto.estimatedAmount),
        notes: dto.notes,
      },
    });
  }

  async list(user: AuthenticatedUser, budgetId: string) {
    await this.assertBudgetAccess(user, budgetId);
    return this.prisma.budgetLine.findMany({
      where: { budgetId },
      include: { repartitionKey: true },
      orderBy: { category: 'asc' },
    });
  }

  async remove(user: AuthenticatedUser, lineId: string) {
    const line = await this.prisma.budgetLine.findUnique({
      where: { id: lineId },
      include: { budget: { include: { fiscalYear: { include: { complex: true } } } } },
    });
    if (!line) throw new NotFoundException('Budget line not found');
    if (!user.isSuperAdmin && line.budget.fiscalYear.complex.tenantId !== user.tenantId) {
      throw new ForbiddenException();
    }
    await this.prisma.budgetLine.delete({ where: { id: lineId } });
    return { deleted: true };
  }

  async upsertBudget(
    user: AuthenticatedUser,
    fiscalYearId: string,
    dto: { totalAmount: number },
  ) {
    const fy = await this.prisma.fiscalYear.findUnique({
      where: { id: fiscalYearId },
      include: { complex: true },
    });
    if (!fy) throw new NotFoundException('Fiscal year not found');
    if (!user.isSuperAdmin && fy.complex.tenantId !== user.tenantId) throw new ForbiddenException();

    const existing = await this.prisma.budget.findFirst({ where: { fiscalYearId } });
    if (existing) {
      return this.prisma.budget.update({
        where: { id: existing.id },
        data: { totalAmount: new Prisma.Decimal(dto.totalAmount) },
      });
    }
    return this.prisma.budget.create({
      data: {
        fiscalYearId,
        totalAmount: new Prisma.Decimal(dto.totalAmount),
      },
    });
  }
}
