package com.writeoff.module.finance.repository;

import com.writeoff.module.finance.model.Payment;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

@Repository
@ConditionalOnProperty(prefix = "app.repository", name = "mode", havingValue = "in-memory")
public class InMemoryPaymentRepository implements PaymentRepository {
    private final ConcurrentHashMap<Long, Payment> store = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<Long, Boolean> projectLockStore = new ConcurrentHashMap<>();
    private final List<Map<String, Object>> reconciliationStore = new ArrayList<>();
    private final List<Map<String, Object>> lockLogStore = new ArrayList<>();
    private final AtomicLong idGenerator = new AtomicLong(9000);

    @Override
    public Payment save(Payment payment) {
        if (payment.getId() == null) {
            Payment newPayment = new Payment(
                    idGenerator.incrementAndGet(),
                    payment.getProjectId(),
                    payment.getMeetingId(),
                    payment.getAmountCent(),
                    payment.getStatus()
            );
            store.put(newPayment.getId(), newPayment);
            return newPayment;
        }
        store.put(payment.getId(), payment);
        return payment;
    }

    @Override
    public List<Payment> findAll() {
        return new ArrayList<>(store.values());
    }

    @Override
    public boolean isProjectLocked(Long projectId) {
        return Boolean.TRUE.equals(projectLockStore.get(projectId));
    }

    @Override
    public void lockProject(Long projectId, String reason, Long operatorUserId) {
        projectLockStore.put(projectId, true);
        Map<String, Object> row = new LinkedHashMap<>();
        row.put("id", lockLogStore.size() + 1L);
        row.put("projectId", projectId);
        row.put("lockStatus", "LOCKED");
        row.put("reason", reason);
        row.put("createdAt", String.valueOf(System.currentTimeMillis()));
        lockLogStore.add(0, row);
    }

    @Override
    public void unlockProject(Long projectId, String reason, Long operatorUserId) {
        projectLockStore.put(projectId, false);
        Map<String, Object> row = new LinkedHashMap<>();
        row.put("id", lockLogStore.size() + 1L);
        row.put("projectId", projectId);
        row.put("lockStatus", "UNLOCKED");
        row.put("reason", reason);
        row.put("createdAt", String.valueOf(System.currentTimeMillis()));
        lockLogStore.add(0, row);
    }

    @Override
    public Map<String, Object> createReconciliation(Long projectId, Long expectedAmountCent, Long operatorUserId) {
        long actual = store.values().stream()
                .filter(x -> x.getProjectId().equals(projectId))
                .mapToLong(Payment::getAmountCent)
                .sum();
        long expected = expectedAmountCent == null ? actual : expectedAmountCent;
        long diff = actual - expected;
        Map<String, Object> row = new LinkedHashMap<>();
        row.put("id", reconciliationStore.size() + 1L);
        row.put("projectId", projectId);
        row.put("expectedAmountCent", expected);
        row.put("actualAmountCent", actual);
        row.put("diffAmountCent", diff);
        row.put("resultStatus", diff == 0 ? "MATCH" : "DIFF");
        row.put("createdAt", String.valueOf(System.currentTimeMillis()));
        reconciliationStore.add(0, row);
        return row;
    }

    @Override
    public List<Map<String, Object>> listReconciliations() {
        return new ArrayList<>(reconciliationStore);
    }

    @Override
    public List<Map<String, Object>> listLockLogs(Long projectId) {
        if (projectId == null) {
            return new ArrayList<>(lockLogStore);
        }
        List<Map<String, Object>> list = new ArrayList<>();
        for (Map<String, Object> row : lockLogStore) {
            if (projectId.equals(row.get("projectId"))) {
                list.add(row);
            }
        }
        return list;
    }
}
