import '../../models/clinic_discount.dart';
import '../../models/job.dart';
import '../../models/prosthetic_product.dart';

class PricingBreakdown {
  const PricingBreakdown({
    required this.billableUnits,
    required this.unitPrice,
    required this.baseAmount,
    required this.discountAmount,
    required this.finalAmount,
    required this.appliedDiscounts,
  });

  final int billableUnits;
  final double unitPrice;
  final double baseAmount;
  final double discountAmount;
  final double finalAmount;
  final List<ClinicDiscount> appliedDiscounts;
}

class PricingService {
  PricingService._();
  static final instance = PricingService._();

  int billableUnitsForType(ProstheticType type, int memberCount) {
    final safeCount = memberCount <= 0 ? 1 : memberCount;
    return switch (type) {
      ProstheticType.hareketli ||
      ProstheticType.tamProtez ||
      ProstheticType.parsiyel =>
        1,
      _ => safeCount,
    };
  }

  int billableUnitsForTeeth(ProstheticType type, Iterable<int> teeth) {
    final selected = teeth.toSet();
    if (selected.isEmpty) return billableUnitsForType(type, 0);
    if (type.family == ProstheticFamily.hareketli) return 1;

    final upper = {
      for (int i = 11; i <= 18; i++) i,
      for (int i = 21; i <= 28; i++) i,
    };
    final lower = {
      for (int i = 31; i <= 38; i++) i,
      for (int i = 41; i <= 48; i++) i,
    };

    var units = 0;
    final remaining = Set<int>.from(selected);
    if (upper.every(selected.contains)) {
      units += 1;
      remaining.removeAll(upper);
    }
    if (lower.every(selected.contains)) {
      units += 1;
      remaining.removeAll(lower);
    }
    return units + remaining.length;
  }

  String unitLabelForType(ProstheticType type) {
    return switch (type) {
      ProstheticType.hareketli ||
      ProstheticType.tamProtez ||
      ProstheticType.parsiyel =>
        'vaka',
      _ => 'diş',
    };
  }

  PricingBreakdown calculate({
    required ProstheticProduct product,
    required ProstheticType prostheticType,
    required int memberCount,
    required String clinicTenantId,
    required List<ClinicDiscount> discounts,
    Iterable<int>? teeth,
  }) {
    final billableUnits = teeth == null
        ? billableUnitsForType(prostheticType, memberCount)
        : billableUnitsForTeeth(prostheticType, teeth);
    final unitPrice = product.unitPrice ?? 0;
    final baseAmount = unitPrice * billableUnits;

    final applicable = discounts.where((discount) {
      if (!discount.isActive) return false;
      if (!(discount.appliesToAll ||
          discount.clinicTenantId == clinicTenantId)) {
        return false;
      }
      if (!(discount.appliesToAllTypes ||
          discount.prostheticType == prostheticType.value)) {
        return false;
      }
      if (discount.minQuantity > 0 && billableUnits < discount.minQuantity) {
        return false;
      }
      return true;
    }).toList();

    double running = baseAmount;
    for (final discount in applicable) {
      running = discount.discountType == DiscountType.percentage
          ? running * (1 - discount.discountValue / 100)
          : running - discount.discountValue;
    }

    final finalAmount = running.clamp(0, double.infinity).toDouble();
    return PricingBreakdown(
      billableUnits: billableUnits,
      unitPrice: unitPrice,
      baseAmount: baseAmount,
      discountAmount:
          (baseAmount - finalAmount).clamp(0, double.infinity).toDouble(),
      finalAmount: finalAmount,
      appliedDiscounts: applicable,
    );
  }
}
