import type { MedicinePricesRepository } from './medicine-prices.repository.js';
import type { MedicineProductsRepository } from '../medicine-products/medicine-products.repository.js';
import type { StoresRepository } from '../stores/stores.repository.js';
import type {
  CreateMedicinePriceRecordInput,
  MedicinePriceHistoryQueryInput,
  MedicinePriceAnalyticsQueryInput,
} from '@meshitrack/shared';
import { NotFoundError } from '../../common/errors.js';

interface Deps {
  medicinePricesRepository: MedicinePricesRepository;
  medicineProductsRepository: MedicineProductsRepository;
  storesRepository: StoresRepository;
}

export class MedicinePricesService {
  private readonly medicinePricesRepository: MedicinePricesRepository;
  private readonly medicineProductsRepository: MedicineProductsRepository;
  private readonly storesRepository: StoresRepository;

  public constructor({
    medicinePricesRepository,
    medicineProductsRepository,
    storesRepository,
  }: Deps) {
    this.medicinePricesRepository = medicinePricesRepository;
    this.medicineProductsRepository = medicineProductsRepository;
    this.storesRepository = storesRepository;
  }

  public async recordPrice(
    data: CreateMedicinePriceRecordInput,
    householdId: string,
    userId: string,
  ) {
    const product = await this.medicineProductsRepository.findById(
      data.medicineProductId,
      householdId,
    );
    if (!product) throw new NotFoundError('Medicine product not found');

    const store = await this.storesRepository.findById(data.storeId, householdId);
    if (!store) throw new NotFoundError('Store not found');

    const pricePerUnit = data.price / data.quantity;
    const date = data.date ? new Date(data.date) : new Date();

    return this.medicinePricesRepository.create({
      householdId,
      medicineProductId: data.medicineProductId,
      medicineProductBrand: product.brand ?? product.medicineName,
      medicineId: data.medicineId,
      medicineName: product.medicineName,
      storeId: data.storeId,
      storeName: store.name,
      price: data.price,
      currency: data.currency,
      quantity: data.quantity,
      unit: data.unit,
      pricePerUnit,
      date,
      isInsurancePrice: data.isInsurancePrice,
      notes: data.notes,
      createdBy: userId,
    });
  }

  public async getPriceHistory(
    householdId: string,
    medicineId: string,
    query: MedicinePriceHistoryQueryInput,
  ) {
    return this.medicinePricesRepository.findByMedicine(householdId, medicineId, query);
  }

  public async compareStores(householdId: string, medicineId: string) {
    return this.medicinePricesRepository.compareStores(householdId, medicineId);
  }

  public async estimatePrice(
    householdId: string,
    medicineId: string,
    storeId?: string,
  ): Promise<number | null> {
    const record = await this.medicinePricesRepository.getLatestForMedicine(
      householdId,
      medicineId,
      storeId,
    );
    return record ? (record.pricePerUnit as number) : null;
  }

  public async getAnalytics(householdId: string, query: MedicinePriceAnalyticsQueryInput) {
    return this.medicinePricesRepository.getAnalytics(householdId, query);
  }
}
