package be.seeseepuff.allowanceplanner.service;

import be.seeseepuff.allowanceplanner.dto.TransferRequest;
import be.seeseepuff.allowanceplanner.entity.Allowance;
import be.seeseepuff.allowanceplanner.repository.AllowanceRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Service
public class TransferService {
    private final AllowanceRepository allowanceRepository;

    public TransferService(AllowanceRepository allowanceRepository) {
        this.allowanceRepository = allowanceRepository;
    }

    @Transactional
    public TransferResult transfer(TransferRequest request) {
        if (request.from() == request.to()) {
            return TransferResult.success();
        }

        int amountCents = (int) Math.round(request.amount() * 100.0);
        if (amountCents <= 0) {
            return TransferResult.badRequest("amount must be positive");
        }

        Optional<Allowance> fromOpt = allowanceRepository.findById(request.from());
        if (fromOpt.isEmpty()) {
            return TransferResult.notFound();
        }

        Optional<Allowance> toOpt = allowanceRepository.findById(request.to());
        if (toOpt.isEmpty()) {
            return TransferResult.notFound();
        }

        Allowance from = fromOpt.get();
        Allowance to = toOpt.get();

        if (from.getUserId() != to.getUserId()) {
            return TransferResult.badRequest("Allowances do not belong to the same user");
        }

        long remainingTo = to.getTarget() - to.getBalance();
        if (remainingTo <= 0) {
            return TransferResult.badRequest("target already reached");
        }

        int transfer = amountCents;
        if (transfer > remainingTo) {
            transfer = (int) remainingTo;
        }

        if (from.getBalance() < transfer) {
            return TransferResult.badRequest("Insufficient funds in source allowance");
        }

        from.setBalance(from.getBalance() - transfer);
        to.setBalance(to.getBalance() + transfer);
        allowanceRepository.save(from);
        allowanceRepository.save(to);

        return TransferResult.success();
    }

    public record TransferResult(Status status, String message) {
        public static TransferResult success() {
            return new TransferResult(Status.SUCCESS, "Transfer successful");
        }

        public static TransferResult badRequest(String message) {
            return new TransferResult(Status.BAD_REQUEST, message);
        }

        public static TransferResult notFound() {
            return new TransferResult(Status.NOT_FOUND, "Allowance not found");
        }

        public enum Status {
            SUCCESS, BAD_REQUEST, NOT_FOUND
        }
    }
}
