package de.effigenix.application.inventory;

import de.effigenix.domain.inventory.*;
import de.effigenix.shared.common.RepositoryError;
import de.effigenix.shared.common.Result;
import de.effigenix.shared.security.ActorId;
import de.effigenix.shared.security.AuthorizationPort;

import java.util.List;

public class ListInventoryCounts {

    private final InventoryCountRepository inventoryCountRepository;
    private final AuthorizationPort authPort;

    public ListInventoryCounts(InventoryCountRepository inventoryCountRepository, AuthorizationPort authPort) {
        this.inventoryCountRepository = inventoryCountRepository;
        this.authPort = authPort;
    }

    public Result<InventoryCountError, List<InventoryCount>> execute(String storageLocationId, String status, ActorId actorId) {
        if (!authPort.can(actorId, InventoryAction.INVENTORY_COUNT_READ)) {
            return Result.failure(new InventoryCountError.Unauthorized("Not authorized to view inventory counts"));
        }

        InventoryCountStatus parsedStatus = null;
        if (status != null) {
            try {
                parsedStatus = InventoryCountStatus.valueOf(status);
            } catch (IllegalArgumentException e) {
                return Result.failure(new InventoryCountError.InvalidStatus(status));
            }
        }

        if (storageLocationId != null) {
            StorageLocationId locId;
            try {
                locId = StorageLocationId.of(storageLocationId);
            } catch (IllegalArgumentException e) {
                return Result.failure(new InventoryCountError.InvalidStorageLocationId(e.getMessage()));
            }
            var result = mapResult(inventoryCountRepository.findByStorageLocationId(locId));
            if (parsedStatus != null) {
                final InventoryCountStatus filterStatus = parsedStatus;
                return result.map(counts -> counts.stream()
                        .filter(c -> c.status() == filterStatus)
                        .toList());
            }
            return result;
        }

        if (parsedStatus != null) {
            return mapResult(inventoryCountRepository.findByStatus(parsedStatus));
        }

        return mapResult(inventoryCountRepository.findAll());
    }

    private Result<InventoryCountError, List<InventoryCount>> mapResult(Result<RepositoryError, List<InventoryCount>> result) {
        return switch (result) {
            case Result.Failure(var err) -> Result.failure(new InventoryCountError.RepositoryFailure(err.message()));
            case Result.Success(var counts) -> Result.success(counts);
        };
    }
}
