package com.writeoff.module.project.repository;

import com.writeoff.module.project.model.Project;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

@Repository
@ConditionalOnProperty(prefix = "app.repository", name = "mode", havingValue = "in-memory")
public class InMemoryProjectRepository implements ProjectRepository {
    private final ConcurrentHashMap<Long, Project> store = new ConcurrentHashMap<>();
    private final AtomicLong idGenerator = new AtomicLong(1000);

    @Override
    public Project save(Project project) {
        if (project.getId() == null) {
            Project newProject = new Project(
                    idGenerator.incrementAndGet(),
                    project.getName(),
                    null,
                    project.getStartDate(),
                    project.getEndDate(),
                    project.getEnterpriseId(),
                    null,
                    project.getHostEnterpriseId(),
                    project.getPartnerEnterpriseId(),
                    project.getHostOwnerUserId(),
                    project.getHostExecutorUserId(),
                    project.getPartnerOwnerUserId(),
                    project.getPartnerExecutorUserId(),
                    project.getBudgetCent(),
                    project.getMeetingTotal(),
                    project.getMeetingCompletedCount(),
                    project.isAllowMeetingOverBudget(),
                    project.getOverBudgetThresholdRatio(),
                    project.getOverBudgetApprovalChainJson(),
                    project.getBudgetExecutionRatio(),
                    project.getRiskFlagsJson(),

                    project.getWriteOffNotStartedCount(),
                    project.getWriteOffInProgressCount(),
                    project.getWriteOffCompletedCount(),
                    project.getLaborFeeRatio(),
                    project.isAllowProjectOverBudget(),
                    project.getInvoiceInfo(),
                    project.getExpenseRatioJson(),
                    project.getHostBackupExecutorUserId(),
                    project.getPartnerBackupExecutorUserId(),
                    project.getProjectOwnerApproverUserId(),
                    project.getFinanceApproverUserId(),
                    project.getTerminatedReason(),
                    project.getFreezeReason(),
                    project.getArchivedAt(),
                    project.getKeyChangeLogJson(),
                    project.getStatus()
            );
            newProject.setSubProjectCount(project.getSubProjectCount());
            newProject.setParentProjectId(project.getParentProjectId());
            newProject.setHostEnterpriseName(project.getHostEnterpriseName());
            newProject.setHostOwnerUsers(project.getHostOwnerUsers());
            newProject.setHostExecutorUsers(project.getHostExecutorUsers());
            newProject.setPartnerOwnerUsers(project.getPartnerOwnerUsers());
            newProject.setPartnerExecutorUsers(project.getPartnerExecutorUsers());
            newProject.setProjectFeeJson(project.getProjectFeeJson());
            store.put(newProject.getId(), newProject);
            return newProject;
        }
        store.put(project.getId(), project);
        return project;
    }

    @Override
    public Optional<Project> findById(Long id) {
        return Optional.ofNullable(store.get(id));
    }

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

    @Override
    public List<Project> findByParentProjectId(Long parentProjectId, boolean includeDeleted) {
        return store.values().stream()
                .filter(project -> {
                    Long currentParentId = project.getParentProjectId();
                    return currentParentId != null && currentParentId.equals(parentProjectId);
                })
                .collect(Collectors.toList());
    }
}
