package com.dne.ems.repository.impl;

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

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Repository;

import com.dne.ems.model.Feedback;
import com.dne.ems.model.Task;
import com.dne.ems.model.enums.TaskStatus;
import com.dne.ems.repository.TaskRepository;
import com.dne.ems.service.JsonStorageService;
import com.fasterxml.jackson.core.type.TypeReference;

import jakarta.annotation.PostConstruct;

@Repository
@Primary
public class JsonTaskRepositoryImpl implements TaskRepository {

    private static final String FILE_NAME = "tasks.json";
    private final JsonStorageService jsonStorageService;
    private final List<Task> taskCache = new ArrayList<>();
    private final AtomicLong idCounter = new AtomicLong(0);

    public JsonTaskRepositoryImpl(JsonStorageService jsonStorageService) {
        this.jsonStorageService = jsonStorageService;
    }

    @PostConstruct
    public void init() {
        List<Task> tasks = jsonStorageService.readData(FILE_NAME, new TypeReference<>() {});
        synchronized (taskCache) {
            taskCache.addAll(tasks);
            long maxId = tasks.stream()
                              .mapToLong(Task::getId)
                              .max()
                              .orElse(0L);
            idCounter.set(maxId);
        }
    }

    @Override
    public Optional<Task> findById(Long id) {
        synchronized (taskCache) {
            return taskCache.stream().filter(t -> t.getId().equals(id)).findFirst();
        }
    }

    @Override
    public List<Task> findAll() {
        synchronized (taskCache) {
            return new ArrayList<>(taskCache);
        }
    }

    @Override
    public Task save(Task task) {
        synchronized (taskCache) {
            if (task.getId() == null) {
                task.setId(idCounter.incrementAndGet());
                taskCache.add(task);
            } else {
                Optional<Task> existing = findById(task.getId());
                if (existing.isPresent()) {
                    taskCache.remove(existing.get());
                }
                taskCache.add(task);
            }
            jsonStorageService.writeData(FILE_NAME, taskCache);
            return task;
        }
    }

    @Override
    public List<Task> saveAll(Iterable<Task> tasks) {
        synchronized (taskCache) {
            List<Task> savedTasks = StreamSupport.stream(tasks.spliterator(), false)
                .map(this::save)
                .collect(Collectors.toList());
            return savedTasks;
        }
    }

    @Override
    public void deleteById(Long id) {
        synchronized (taskCache) {
            taskCache.removeIf(task -> task.getId().equals(id));
            jsonStorageService.writeData(FILE_NAME, taskCache);
        }
    }

    @Override
    public void deleteAll() {
        synchronized (taskCache) {
            taskCache.clear();
            jsonStorageService.writeData(FILE_NAME, taskCache);
        }
    }

    @Override
    public boolean existsById(Long id) {
        synchronized (taskCache) {
            return taskCache.stream().anyMatch(t -> t.getId().equals(id));
        }
    }

    @Override
    public long count() {
        synchronized (taskCache) {
            return taskCache.size();
        }
    }

    @Override
    public Optional<Task> findByFeedback(Feedback feedback) {
        synchronized (taskCache) {
            return taskCache.stream()
                .filter(task -> task.getFeedback() != null && task.getFeedback().equals(feedback))
                .findFirst();
        }
    }

    @Override
    public long countByStatus(TaskStatus status) {
        synchronized (taskCache) {
            return taskCache.stream().filter(task -> task.getStatus() == status).count();
        }
    }

    @Override
    public long countByAssigneeIdAndStatusIn(Long assigneeId, Collection<TaskStatus> statuses) {
        synchronized (taskCache) {
            return taskCache.stream()
                .filter(task -> task.getAssignee() != null && task.getAssignee().getId().equals(assigneeId))
                .filter(task -> statuses.contains(task.getStatus()))
                .count();
        }
    }

    @Override
    public List<Task> findByAssigneeIdAndStatus(Long assigneeId, TaskStatus status) {
        synchronized (taskCache) {
            return taskCache.stream()
                .filter(task -> task.getAssignee() != null && task.getAssignee().getId().equals(assigneeId))
                .filter(task -> task.getStatus() == status)
                .collect(Collectors.toList());
        }
    }
} 