import type { MedicinesRepository } from './medicines.repository.js';
import type { MedicineProductsRepository } from '../medicine-products/medicine-products.repository.js';
import type {
  CreateMedicineInput,
  UpdateMedicineInput,
  MedicineQueryInput,
} from '@meshitrack/shared';
import { NotFoundError, ConflictError } from '../../common/errors.js';

interface Deps {
  medicinesRepository: MedicinesRepository;
  medicineProductsRepository: MedicineProductsRepository;
}

export class MedicinesService {
  private readonly medicinesRepository: MedicinesRepository;
  private readonly medicineProductsRepository: MedicineProductsRepository;

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

  public async list(householdId: string, query: MedicineQueryInput) {
    return this.medicinesRepository.findByHousehold(householdId, query);
  }

  public async getById(id: string, householdId: string) {
    const medicine = await this.medicinesRepository.findById(id, householdId);
    if (!medicine) {
      throw new NotFoundError('Medicine not found');
    }
    return medicine;
  }

  public async create(data: CreateMedicineInput, householdId: string, createdBy: string) {
    const existing = await this.medicinesRepository.findDuplicate(
      householdId,
      data.name,
      data.strength,
      data.strengthUnit,
      data.form,
    );
    if (existing) {
      throw new ConflictError('A medicine with the same name, strength, and form already exists');
    }
    return this.medicinesRepository.create(data, householdId, createdBy);
  }

  public async update(id: string, householdId: string, data: UpdateMedicineInput) {
    await this.getById(id, householdId);

    if (data.name || data.strength || data.strengthUnit || data.form) {
      const current = await this.medicinesRepository.findById(id, householdId);
      const name = data.name ?? current!.name;
      const strength = data.strength ?? current!.strength;
      const strengthUnit = data.strengthUnit ?? current!.strengthUnit;
      const form = data.form ?? current!.form;

      const duplicate = await this.medicinesRepository.findDuplicate(
        householdId,
        name,
        strength,
        strengthUnit,
        form,
        id,
      );
      if (duplicate) {
        throw new ConflictError('A medicine with the same name, strength, and form already exists');
      }
    }

    const updated = await this.medicinesRepository.update(id, householdId, data);
    if (!updated) throw new NotFoundError('Medicine not found');
    return updated;
  }

  public async delete(id: string, householdId: string) {
    await this.getById(id, householdId);

    const productCount = await this.medicineProductsRepository.countByMedicineId(id);
    if (productCount > 0) {
      throw new ConflictError(
        `Cannot delete medicine with ${productCount} linked product(s). Delete them first.`,
      );
    }

    const deleted = await this.medicinesRepository.softDelete(id, householdId);
    if (!deleted) throw new NotFoundError('Medicine not found');
    return deleted;
  }
}
